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
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
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
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