Exemplo n.º 1
0
    def test_location_resolving(self):
        # test basic address lookup -- ensure zip and geocoding info is filled in
        # https://maps.googleapis.com/maps/api/geocode/json?address=3411+Blvd+of+the+Allies&region=US&sensor=false
        resolved = pl_outsourcing.resolve_location(Location(address='3411 Blvd of the Allies'))
        self.assertEquals(resolved.address,'3411 Boulevard of the Allies')
        self.assertEquals(resolved.postcode,'15213')
        self.assertEquals(resolved.town,'Pittsburgh')
        self.assertEquals(resolved.state,'PA')
        self.assertEquals(resolved.country,'US')
        self.assertAlmostEquals(resolved.latitude,40.435938,3)   # assert equals up to 2 places
        self.assertAlmostEquals(resolved.longitude,-79.958309,3)

        # test zip codes properly bias searches -- if these fail, make sure the geocoding info
        # at the following links matches the expected values below:
        # https://maps.googleapis.com/maps/api/geocode/json?address=800+penn+ave%2C+15222&region=US&sensor=false
        # https://maps.googleapis.com/maps/api/geocode/json?address=800+penn+ave%2C+15221&region=US&sensor=false
        resolved = pl_outsourcing.resolve_location(Location(address='800 penn ave',postcode='15222'))
        self.assertAlmostEquals(resolved.latitude,40.443290,places=4)   # assert equals up to 2 places
        self.assertAlmostEquals(resolved.longitude,-79.999092,places=2)
        resolved = pl_outsourcing.resolve_location(Location(address='800 penn ave',postcode='15221'))
        self.assertAlmostEquals(resolved.latitude,40.442470,4)   # assert equals up to 2 places
        self.assertAlmostEquals(resolved.longitude,-79.881871,2)        

        # tests that geocoding info properly biases searches
        # expected results are based on the following geocoding API calls:
        # http://maps.googleapis.com/maps/api/geocode/json?region=US&sensor=false&bounds=40.438000%2C-80.005000%7C40.448000%2C-79.995000&address=800+penn+ave
        # http://maps.googleapis.com/maps/api/geocode/json?region=US&sensor=false&bounds=40.437000%2C-79.905000%7C40.447000%2C-79.895000&address=800+penn+ave
        resolved = pl_outsourcing.resolve_location(Location(address='800 penn ave',latitude=40.443,longitude=-80))
        self.assertEquals(resolved.postcode,'15222')
        resolved = pl_outsourcing.resolve_location(Location(address='800 penn ave',latitude=40.442,longitude=-79.9))
        self.assertEquals(resolved.postcode,'15221')

        # bad address
        unresolved = pl_outsourcing.resolve_location(Location(address='fakey fake double false address'))
        self.assertIsNone(unresolved)
Exemplo n.º 2
0
    def test_location_resolving(self):
        # test basic address lookup -- ensure zip and geocoding info is filled in
        # https://maps.googleapis.com/maps/api/geocode/json?address=3411+Blvd+of+the+Allies&region=US&sensor=false
        resolved = pl_outsourcing.resolve_location(
            Location(address='3411 Blvd of the Allies'))
        self.assertEquals(resolved.address, '3411 Boulevard of the Allies')
        self.assertEquals(resolved.postcode, '15213')
        self.assertEquals(resolved.town, 'Pittsburgh')
        self.assertEquals(resolved.state, 'PA')
        self.assertEquals(resolved.country, 'US')
        self.assertAlmostEquals(resolved.latitude, 40.435938,
                                3)  # assert equals up to 2 places
        self.assertAlmostEquals(resolved.longitude, -79.958309, 3)

        # test zip codes properly bias searches -- if these fail, make sure the geocoding info
        # at the following links matches the expected values below:
        # https://maps.googleapis.com/maps/api/geocode/json?address=800+penn+ave%2C+15222&region=US&sensor=false
        # https://maps.googleapis.com/maps/api/geocode/json?address=800+penn+ave%2C+15221&region=US&sensor=false
        resolved = pl_outsourcing.resolve_location(
            Location(address='800 penn ave', postcode='15222'))
        self.assertAlmostEquals(resolved.latitude, 40.443290,
                                places=4)  # assert equals up to 2 places
        self.assertAlmostEquals(resolved.longitude, -79.999092, places=2)
        resolved = pl_outsourcing.resolve_location(
            Location(address='800 penn ave', postcode='15221'))
        self.assertAlmostEquals(resolved.latitude, 40.442470,
                                4)  # assert equals up to 2 places
        self.assertAlmostEquals(resolved.longitude, -79.881871, 2)

        # tests that geocoding info properly biases searches
        # expected results are based on the following geocoding API calls:
        # http://maps.googleapis.com/maps/api/geocode/json?region=US&sensor=false&bounds=40.438000%2C-80.005000%7C40.448000%2C-79.995000&address=800+penn+ave
        # http://maps.googleapis.com/maps/api/geocode/json?region=US&sensor=false&bounds=40.437000%2C-79.905000%7C40.447000%2C-79.895000&address=800+penn+ave
        resolved = pl_outsourcing.resolve_location(
            Location(address='800 penn ave', latitude=40.443, longitude=-80))
        self.assertEquals(resolved.postcode, '15222')
        resolved = pl_outsourcing.resolve_location(
            Location(address='800 penn ave', latitude=40.442, longitude=-79.9))
        self.assertEquals(resolved.postcode, '15221')

        # bad address
        unresolved = pl_outsourcing.resolve_location(
            Location(address='fakey fake double false address'))
        self.assertIsNone(unresolved)
Exemplo n.º 3
0
def store_fbpage_place(page_info, create_owner=True):
    '''
    Takes a dict of properties retreived from a Facebook Graph API call for
    a page and stores a Place from the information. The following 
    fields in the dict are used:
    - id          (required)
    - type        (required with value 'page' or a TypeError will be thrown)
    - location    (required or TypeError will be thrown)
    - description
    - url
    - phone
    - hours
    - picture

    No new Place will be returned if either an identical one already
    exists in the db, or an ExternalPlaceSource already exists for 
    the given Facebook id. An INFO message is logged to note the attempt 
    to store an existing page as a Place.

    If create_owner is True a new Organization will be created from the same
    page information if one does not already exist.
    '''
    pid = page_info['id']

    try:
        place = ExternalPlaceSource.objects.get(service='fb', uid=pid).place
        outsourcing_log.info('Existing fb page Place found for fbid %s' %
                             unicode(pid))
        return place
    except ExternalPlaceSource.DoesNotExist:
        pass

    if page_info.get('type') != 'page':
        raise TypeError("Cannot store object without 'page' type as a Place.")
    elif 'location' not in page_info:
        raise TypeError("Cannot store object without location key as a Place.")

    pname = page_info['name'].strip()

    ### Figure out the new Place's location field
    fbloc = page_info['location']
    if 'id' in fbloc:
        # TODO: need to ensure fbloc_to_loc can handle ids in location if this ever happens
        outsourcing_log.info('Facebook page %s has id in location (%s)' %
                             (pid, fbloc['id']))
    location = fbloc_to_loc(fbloc)

    # if there's no address or geocoding, we'll need to talk to outside services
    if not location.address:
        seed_place = Place(name=pname, location=location)
        resolved_place = resolve_place(seed_place)
        if resolved_place:
            location = resolved_place.location

    # really want geolocation, go to Google Geocoding for it if we need it
    if location.longitude is None or location.latitude is None:
        seed_loc = copy.deepcopy(location)
        resolved_location = resolve_location(seed_loc, allow_numberless=False)
        if resolved_location:
            location = resolved_location

    # if there's no specific address information, make the error radius around the
    # lat/lng super tight. Don't want to create whirlpools.
    cl_opts = dict(lat_error=1e-5,
                   lng_error=1e-5) if not location.address else {}

    location, created = Location.close_manager.get_close_or_create(
        address=location.address,
        postcode=location.postcode,
        town=location.town,
        state=location.state,
        country=location.country,
        neighborhood=location.neighborhood,
        latitude=location.latitude,
        longitude=location.longitude,
        _close_options=cl_opts)
    if created:
        outsourcing_log.debug('Saved new location "%s"' % location.full_string)
    else:
        outsourcing_log.debug('Retrieved existing location "%s"' %
                              location.full_string)

    try:
        owner = FacebookOrgRecord.objects.get(fb_id=pid).organization
    except FacebookOrgRecord.DoesNotExist:
        if create_owner:
            outsourcing_log.info(
                'Creating new Organization as byproduct of creating Place from Facebook page %s'
                % unicode(pid))
            owner = store_fbpage_organization(page_info)
        else:
            owner = None

    place, created = Place.objects.get_or_create(name=pname[:200],
                                                 description=page_info.get(
                                                     'description',
                                                     '').strip(),
                                                 location=location,
                                                 owner=owner)

    # add place meta info that exists
    _store_fbpage_placemeta(page_info, place)

    # create a new link to an external id
    ExternalPlaceSource.objects.create(service='fb', uid=pid, place=place)
    return place
Exemplo n.º 4
0
def run():
    in_filename = os.path.join(os.path.dirname(__file__), 'obid.csv')

    #clear all tables
    Location.objects.all().delete()
    PlaceMeta.objects.all().delete()
    Place.objects.all().delete()
    Organization.objects.all().delete()
    ExternalPlaceSource.objects.all().delete()
    FacebookPage.objects.all().delete()
    FacebookOrgRecord.objects.all().delete()

    gplaces_category_map = load_category_map('google_places')
    gp_hits, gp_misses = 0, 0

    rows = OBIDRow.rows_from_csv(in_filename)

    # cycle through each row with a facebook reference and store a reference
    page_mgr = PageImportManager()
    fb_rows = [row for row in rows if row.fb_id]
    for row, info in zip(
            fb_rows, page_mgr.pull_page_info([row.fb_id for row in fb_rows])):
        if isinstance(info, dict):
            info.pop('metadata',
                     None)  # don't need to store metadata if it exists
            FacebookPage.objects.get_or_create(
                fb_id=info['id'],
                defaults=dict(pageinfo_json=json.dumps(info)))
            row.fb_id = info['id']  # ensure a numeric id
        else:
            print 'ERROR: Pulling fb page %s resulted in the following exception: "%s"' % (
                str(row.fb_id), str(info))
            row.fb_id = ''

    # cycle through all rows and store everything
    for i, row in enumerate(rows):
        if not row.place:
            print 'ERROR: no place for entry %d' % i

        # resolve the location
        location = resolve_location(
            Location(address=row.address, postcode='15213'))

        if location:
            # hack to get around Google Geocoding appending the unviersity onto all addresses
            if ( location.address.startswith('University') and not row.address.lower().startswith('univ') ) or \
               ( location.address.startswith('Carnegie Mellon') and row.address.lower().startswith('carnegie mellon') ):
                location.address = ','.join(location.address.split(',')[1:])

            try:
                # if exact match exists, use it instead of the newly found one
                location = Location.objects.get(address=location.address,
                                                postcode=location.postcode)
            except Location.DoesNotExist:
                location.save()
        else:
            print 'WARNING: Geocoding failed for entry %d ("%s")' % (i,
                                                                     row.place)

        diff_org = row.org != row.place
        org, place = None, None

        # import org
        # if the row has a fb id, we'll try to import the Org from Facebook
        # only import Org from Facebook if it's the same as the Place (fb id relates to place only)
        if row.fb_id and not diff_org:
            try:
                org = FacebookOrgRecord.objects.get(fb_id=row.fb_id)
            except FacebookOrgRecord.DoesNotExist:
                report = page_mgr.import_org(row.fb_id)
                if report.model_instance:
                    org = report.model_instance
                else:
                    print 'WARNING: Organization FB import failed for entry %d (fbid %s)' % (
                        i, str(row.fb_id))

        if not org:
            org, created = Organization.objects.get_or_create(name=row.org)

        # import place
        if row.fb_id:
            try:
                place = ExternalPlaceSource.facebook.get(uid=row.fb_id)
            except ExternalPlaceSource.DoesNotExist:
                report = page_mgr.import_place(row.fb_id, import_owners=False)
                if report.model_instance:
                    place = report.model_instance
                    if not place.owner:  # no owner is created automatically, so set it if not created
                        place.owner = org
                        place.save()
                else:
                    print 'WARNING: Place FB import failed for entry %d (fbid %s)' % (
                        i, str(row.fb_id))

        if not place:
            place, created = Place.objects.get_or_create(name=row.place,
                                                         location=location,
                                                         owner=org)

        if row.url:
            PlaceMeta.objects.create(place=place,
                                     meta_key='url',
                                     meta_value=row.url)
            if not diff_org:  # also save the url as the org's url if they're the same
                org.url = row.url
                org.save()

        if row.phone:
            PlaceMeta.objects.create(place=place,
                                     meta_key='phone',
                                     meta_value=row.phone)

        print 'Imported %s' % row.place
        try:
            print '  (linked to FB page %s)' % ExternalPlaceSource.facebook.get(
                place=place).uid
        except ExternalPlaceSource.DoesNotExist:
            pass

        # store tags from Google Place lookup
        if location and \
            location.latitude is not None and location.longitude is not None:
            coords = (location.latitude, location.longitude)
            radius = 1000
        else:
            coords = (40.4425, -79.9575)
            radius = 5000

        response = gplaces_client.search_request(coords,
                                                 radius,
                                                 keyword=row.place)

        if len(response) > 0 and 'reference' in response[0]:
            details = gplaces_client.details_request(response[0]['reference'])
            all_tags = set()
            for typ in details.get('types', []):
                if typ in gplaces_category_map:
                    all_tags.update(gplaces_category_map[typ])
                else:
                    print 'WARNING: Unknown Google Places type: "%s"' % typ
            if len(all_tags) > 0:
                print '  Tags:',
                for t in all_tags:
                    print '%s,' % t,
                print
            gp_hits += 1
        else:
            print '  WARNING: Failure querying Google Places for "%s" within %dm of (%f,%f)' % (
                row.place, radius, coords[0], coords[1])
            gp_misses += 1
    print gp_hits, gp_misses
Exemplo n.º 5
0
def run():
    in_filename = os.path.join(os.path.dirname(__file__),'obid.csv')

    #clear all tables
    Location.objects.all().delete()
    PlaceMeta.objects.all().delete()
    Place.objects.all().delete()
    Organization.objects.all().delete()
    ExternalPlaceSource.objects.all().delete()
    FacebookPage.objects.all().delete()
    FacebookOrgRecord.objects.all().delete()

    gplaces_category_map = load_category_map('google_places')
    gp_hits, gp_misses = 0,0

    rows = OBIDRow.rows_from_csv(in_filename)
    
    # cycle through each row with a facebook reference and store a reference
    page_mgr = PageImportManager()
    fb_rows = [row for row in rows if row.fb_id]
    for row,info in zip(fb_rows,page_mgr.pull_page_info([row.fb_id for row in fb_rows])):
        if isinstance(info,dict):
            info.pop('metadata',None)       # don't need to store metadata if it exists
            FacebookPage.objects.get_or_create(fb_id=info['id'],
                                        defaults=dict(pageinfo_json=json.dumps(info)))
            row.fb_id = info['id']  # ensure a numeric id
        else:
            print 'ERROR: Pulling fb page %s resulted in the following exception: "%s"' % (str(row.fb_id),str(info))
            row.fb_id = ''

    # cycle through all rows and store everything
    for i,row in enumerate(rows):
        if not row.place:
            print 'ERROR: no place for entry %d' % i
        
        # resolve the location
        location = resolve_location(Location(address=row.address,postcode='15213'))

        if location:
            # hack to get around Google Geocoding appending the unviersity onto all addresses
            if ( location.address.startswith('University') and not row.address.lower().startswith('univ') ) or \
               ( location.address.startswith('Carnegie Mellon') and row.address.lower().startswith('carnegie mellon') ):
               location.address = ','.join(location.address.split(',')[1:])

            try:
                # if exact match exists, use it instead of the newly found one
                location = Location.objects.get(address=location.address,postcode=location.postcode)
            except Location.DoesNotExist:
                location.save()
        else:
            print 'WARNING: Geocoding failed for entry %d ("%s")' % (i,row.place)

        diff_org = row.org != row.place
        org, place = None, None

        # import org
        # if the row has a fb id, we'll try to import the Org from Facebook
        # only import Org from Facebook if it's the same as the Place (fb id relates to place only)
        if row.fb_id and not diff_org:
            try:
                org = FacebookOrgRecord.objects.get(fb_id=row.fb_id)
            except FacebookOrgRecord.DoesNotExist:
                report = page_mgr.import_org(row.fb_id)
                if report.model_instance:
                    org = report.model_instance
                else:
                    print 'WARNING: Organization FB import failed for entry %d (fbid %s)' % (i,str(row.fb_id))

        if not org:
            org,created = Organization.objects.get_or_create(name=row.org)

        # import place
        if row.fb_id:
            try:
                place = ExternalPlaceSource.facebook.get(uid=row.fb_id)
            except ExternalPlaceSource.DoesNotExist:
                report = page_mgr.import_place(row.fb_id,import_owners=False)
                if report.model_instance:
                    place = report.model_instance
                    if not place.owner:     # no owner is created automatically, so set it if not created
                        place.owner = org
                        place.save()
                else:
                    print 'WARNING: Place FB import failed for entry %d (fbid %s)' % (i,str(row.fb_id))
        
        if not place:
            place,created = Place.objects.get_or_create(name=row.place,location=location,owner=org)
        
        if row.url:
            PlaceMeta.objects.create(place=place,meta_key='url',meta_value=row.url)
            if not diff_org:    # also save the url as the org's url if they're the same
                org.url = row.url
                org.save()

        if row.phone:
            PlaceMeta.objects.create(place=place,meta_key='phone',meta_value=row.phone)

        print 'Imported %s' % row.place
        try:
            print '  (linked to FB page %s)' % ExternalPlaceSource.facebook.get(place=place).uid
        except ExternalPlaceSource.DoesNotExist:
            pass

        # store tags from Google Place lookup
        if location and \
            location.latitude is not None and location.longitude is not None:
            coords = (location.latitude,location.longitude)
            radius = 1000
        else:
            coords = (40.4425,-79.9575)
            radius = 5000

        response = gplaces_client.search_request(coords,radius,keyword=row.place)

        if len(response) > 0 and 'reference' in response[0]:
            details = gplaces_client.details_request(response[0]['reference'])
            all_tags = set()
            for typ in details.get('types',[]):
                if typ in gplaces_category_map:
                    all_tags.update(gplaces_category_map[typ])
                else:
                    print 'WARNING: Unknown Google Places type: "%s"' % typ
            if len(all_tags) > 0:
                print '  Tags:',
                for t in all_tags:
                    print '%s,' % t,
                print
            gp_hits += 1
        else:
            print '  WARNING: Failure querying Google Places for "%s" within %dm of (%f,%f)' % (row.place,radius,coords[0],coords[1])
            gp_misses += 1
    print gp_hits, gp_misses
Exemplo n.º 6
0
def store_fbpage_place(page_info,create_owner=True):
    '''
    Takes a dict of properties retreived from a Facebook Graph API call for
    a page and stores a Place from the information. The following 
    fields in the dict are used:
    - id          (required)
    - type        (required with value 'page' or a TypeError will be thrown)
    - location    (required or TypeError will be thrown)
    - description
    - url
    - phone
    - hours
    - picture

    No new Place will be returned if either an identical one already
    exists in the db, or an ExternalPlaceSource already exists for 
    the given Facebook id. An INFO message is logged to note the attempt 
    to store an existing page as a Place.

    If create_owner is True a new Organization will be created from the same
    page information if one does not already exist.
    '''
    pid = page_info['id']
    
    try:
        place = ExternalPlaceSource.objects.get(service='fb',uid=pid).place
        outsourcing_log.info('Existing fb page Place found for fbid %s' % unicode(pid))
        return place
    except ExternalPlaceSource.DoesNotExist:
        pass

    if page_info.get('type') != 'page':
        raise TypeError("Cannot store object without 'page' type as a Place.")
    elif 'location' not in page_info:
        raise TypeError("Cannot store object without location key as a Place.")
    
    pname = page_info['name'].strip()

    ### Figure out the new Place's location field
    fbloc = page_info['location']
    if 'id' in fbloc:
        # TODO: need to ensure fbloc_to_loc can handle ids in location if this ever happens
        outsourcing_log.info('Facebook page %s has id in location (%s)' % (pid,fbloc['id']))
    location = fbloc_to_loc(fbloc)

    # if there's no address or geocoding, we'll need to talk to outside services
    if not location.address:
        seed_place = Place(name=pname,location=location)
        resolved_place = resolve_place(seed_place)
        if resolved_place:
            location = resolved_place.location
    
    # really want geolocation, go to Google Geocoding for it if we need it
    if location.longitude is None or location.latitude is None:
        seed_loc = copy.deepcopy(location)
        resolved_location = resolve_location(seed_loc,allow_numberless=False)
        if resolved_location: 
            location = resolved_location

    # if there's no specific address information, make the error radius around the
    # lat/lng super tight. Don't want to create whirlpools. 
    cl_opts = dict(lat_error=1e-5,lng_error=1e-5) if not location.address else {}
    
    location, created = Location.close_manager.get_close_or_create(
                    address=location.address,
                    postcode=location.postcode,
                    town=location.town,
                    state=location.state,
                    country=location.country,
                    neighborhood=location.neighborhood,
                    latitude=location.latitude,
                    longitude=location.longitude,
                    _close_options=cl_opts)
    if created:
        outsourcing_log.debug('Saved new location "%s"' % location.full_string)
    else:
        outsourcing_log.debug('Retrieved existing location "%s"' % location.full_string)

    try:
        owner = FacebookOrgRecord.objects.get(fb_id=pid).organization
    except FacebookOrgRecord.DoesNotExist:
        if create_owner:
            outsourcing_log.info('Creating new Organization as byproduct of creating Place from Facebook page %s' % unicode(pid))
            owner = store_fbpage_organization(page_info)
        else:
            owner = None

    place, created = Place.objects.get_or_create(name=pname[:200],
                        description=page_info.get('description','').strip(),
                        location=location,
                        owner=owner)

    # add place meta info that exists      
    _store_fbpage_placemeta(page_info,place)

    # create a new link to an external id
    ExternalPlaceSource.objects.create(service='fb',uid=pid,
                                        place=place)
    return place
Exemplo n.º 7
0
def _process_place(event_info):
    '''
    Attempts to tease a Place out of the given event_info. 

    May return either an already stored Place or a non-stored one (check 
    the pk value to tell the difference).

    Important! If Place is not yet stored, the Location inside it is not
    guaranteed to be stored either. Ensure the inner Location is saved 
    before saving the Place!
    '''
    venue = event_info.get('venue',{})
    place_name = event_info.get('location','').strip()
    if venue.get('id'):
        # best case is that our venue is identified by an existing Facebook ID
        try:
            return ExternalPlaceSource.facebook.get(uid=venue.get('id')).place
        except ExternalPlaceSource.DoesNotExist:
            pass

    # we couldn't get a nice id-based Place, so we're going to try to figure one 
    # out manually if there's vanue or place_name fields 
    if venue or place_name:
        # do something semi-intelligent to get a good Location out of the venue
        if venue:
            location = fbpages.fbloc_to_loc(venue)
            # if there's no address or geocoding, we'll need to talk to outside services
            if not location.address:
                # try to build a seed to resolve with
                seed_loc = copy.deepcopy(location)
                
                # in the absense of city/state info, assume location is in same city/state as owner
                if not seed_loc.town or not seed_loc.state:
                    fbowner = event_info.get('owner',{})
                    if fbowner.get('id'):
                        try:
                            owner_place = ExternalPlaceSource.facebook.get(uid=fbowner.get('id')).place
                        except ExternalPlaceSource.DoesNotExist:
                            owner_place = None
                        if owner_place:
                            if not seed_loc.town:
                                seed_loc.town = owner_place.location.town
                            if not seed_loc.state:
                                seed_loc.state = owner_place.location.state

                seed_place = Place(name=place_name,location=seed_loc)
                resolved_place = resolve_place(seed_place)
                if resolved_place:
                    # throw awy everything but the location
                    location = resolved_place.location
            
            # really want geolocation, go to Google Geocoding for it if we need it
            if location.longitude is None or location.latitude is None:
                seed_loc = copy.deepcopy(location)
                resolved_location = resolve_location(seed_loc)
                if resolved_location: 
                    location = resolved_location
            
            # if there's a "close enough" location in the db already, find and use it
            # only want to include "not-null" arguments into the get_close call. find these here
            # if still no geocoding info, 
            has_geocoding = location.latitude is not None and location.longitude is not None
            if has_geocoding:
                # since we've got geocoding info, this location is specific. therefore, null entries 
                # just signify a lack of info, not a planned null field for a vague address: omit them 
                # for the get query
                kwargs = _location_to_kwargs(location,True)  
                try:
                    location = Location.close_manager.get_close(**kwargs)
                except Location.DoesNotExist:   # if none found, no biggie, just return
                    pass
            else:
                # if we don't have geocoding, we want to find an exact match in the db, null fields and all
                kwargs = _location_to_kwargs(location,False) 
                try:
                    location = Location.objects.get(**kwargs)
                except Location.DoesNotExist:   
                    # if none found, no biggie, just return
                    pass
                except Location.MultipleObjectsReturned:
                    # if more than one found, its a sign there's some dups in the db. just return the first one.
                    outsourcing_log.warning('Multiple objects returned with Location query of %s' % unicode(kwargs))
                    return Location.objects.filter(**kwargs)[0]
        else:
            location = None

        return Place(name=place_name,location=location)
            
    # worst case: we assume the event is happening at the location specified by the
    #   owners fbid (assuming this fbid is already linked to a place)
    fbowner_id = event_info.get('owner',{}).get('id')
    if fbowner_id:
        # TODO: try harder to resolve owner place? isolated event creation will always fail here
        try:
            return ExternalPlaceSource.facebook.get(uid=fbowner_id).place
        except ExternalPlaceSource.DoesNotExist:
            pass
    
    return None
Exemplo n.º 8
0
def _process_place(event_info):
    '''
    Attempts to tease a Place out of the given event_info. 

    May return either an already stored Place or a non-stored one (check 
    the pk value to tell the difference).

    Important! If Place is not yet stored, the Location inside it is not
    guaranteed to be stored either. Ensure the inner Location is saved 
    before saving the Place!
    '''
    venue = event_info.get('venue', {})
    place_name = event_info.get('location', '').strip()
    if venue.get('id'):
        # best case is that our venue is identified by an existing Facebook ID
        try:
            return ExternalPlaceSource.facebook.get(uid=venue.get('id')).place
        except ExternalPlaceSource.DoesNotExist:
            pass

    # we couldn't get a nice id-based Place, so we're going to try to figure one
    # out manually if there's vanue or place_name fields
    if venue or place_name:
        # do something semi-intelligent to get a good Location out of the venue
        if venue:
            location = fbpages.fbloc_to_loc(venue)
            # if there's no address or geocoding, we'll need to talk to outside services
            if not location.address:
                # try to build a seed to resolve with
                seed_loc = copy.deepcopy(location)

                # in the absense of city/state info, assume location is in same city/state as owner
                if not seed_loc.town or not seed_loc.state:
                    fbowner = event_info.get('owner', {})
                    if fbowner.get('id'):
                        try:
                            owner_place = ExternalPlaceSource.facebook.get(
                                uid=fbowner.get('id')).place
                        except ExternalPlaceSource.DoesNotExist:
                            owner_place = None
                        if owner_place:
                            if not seed_loc.town:
                                seed_loc.town = owner_place.location.town
                            if not seed_loc.state:
                                seed_loc.state = owner_place.location.state

                seed_place = Place(name=place_name, location=seed_loc)
                resolved_place = resolve_place(seed_place)
                if resolved_place:
                    # throw awy everything but the location
                    location = resolved_place.location

            # really want geolocation, go to Google Geocoding for it if we need it
            if location.longitude is None or location.latitude is None:
                seed_loc = copy.deepcopy(location)
                resolved_location = resolve_location(seed_loc)
                if resolved_location:
                    location = resolved_location

            # if there's a "close enough" location in the db already, find and use it
            # only want to include "not-null" arguments into the get_close call. find these here
            # if still no geocoding info,
            has_geocoding = location.latitude is not None and location.longitude is not None
            if has_geocoding:
                # since we've got geocoding info, this location is specific. therefore, null entries
                # just signify a lack of info, not a planned null field for a vague address: omit them
                # for the get query
                kwargs = _location_to_kwargs(location, True)
                try:
                    location = Location.close_manager.get_close(**kwargs)
                except Location.DoesNotExist:  # if none found, no biggie, just return
                    pass
            else:
                # if we don't have geocoding, we want to find an exact match in the db, null fields and all
                kwargs = _location_to_kwargs(location, False)
                try:
                    location = Location.objects.get(**kwargs)
                except Location.DoesNotExist:
                    # if none found, no biggie, just return
                    pass
                except Location.MultipleObjectsReturned:
                    # if more than one found, its a sign there's some dups in the db. just return the first one.
                    outsourcing_log.warning(
                        'Multiple objects returned with Location query of %s' %
                        unicode(kwargs))
                    return Location.objects.filter(**kwargs)[0]
        else:
            location = None

        return Place(name=place_name, location=location)

    # worst case: we assume the event is happening at the location specified by the
    #   owners fbid (assuming this fbid is already linked to a place)
    fbowner_id = event_info.get('owner', {}).get('id')
    if fbowner_id:
        # TODO: try harder to resolve owner place? isolated event creation will always fail here
        try:
            return ExternalPlaceSource.facebook.get(uid=fbowner_id).place
        except ExternalPlaceSource.DoesNotExist:
            pass

    return None