def get(self): self.response.headers['Content-Type'] = 'text/plain' access_token = None real_key = self.request.get('key') if not real_key: fb_uid = self.request.get('fb_uid') fbl = fb_api.FBLookup(fb_uid, access_token) fbtype_lookup = { 'OBJ_PROFILE': fb_api.LookupProfile, 'OBJ_USER': fb_api.LookupUser, 'OBJ_USER_EVENTS': fb_api.LookupUserEvents, 'OBJ_EVENT': fb_api.LookupEvent, 'OBJ_EVENT_MEMBERS': fb_api.LookupEventMembers, 'OBJ_THING_FEED': fb_api.LookupThingCommon, 'OBJ_THING_USER': fb_api.LookupThingUser, 'OBJ_THING_GROUP': fb_api.LookupThingGroup, 'OBJ_THING_PAGE': fb_api.LookupThingPage, } req_type = self.request.get('type') if req_type in fbtype_lookup: fbtype = fbtype_lookup[req_type] else: self.response.out.write('type %s must be one of %s' % (req_type, fbtype_lookup.keys())) return key = fb_api.generate_key(fbtype, self.request.get('arg')) real_key = fbl.key_to_cache_key(key) memcache_result = memcache.get(real_key) db_result = fb_api.FacebookCachedObject.get_by_key_name(real_key) if not db_result: self.response.set_status(404) return self.response.out.write('Database Date:\n%s\n\n' % db_result.date_cached) self.response.out.write('Memcache:\n%s\n\n' % pprint.pformat(memcache_result, width=200)) self.response.out.write('Database:\n%s\n\n' % pprint.pformat( db_result and db_result.decode_data() or None, width=200)) self.response.out.write('MemcacheJSON:\n%s\n\n' % json.dumps(memcache_result)) self.response.out.write( 'DatabaseJSON:\n%s\n\n' % json.dumps(db_result and db_result.decode_data() or None))
def _facebook_weekly_post(db_auth_token, city_data): city_key = city_data['city'] city = cities.City.get_by_key_name(city_key) page_id = db_auth_token.token_nickname fbl = fb_api.FBLookup(None, db_auth_token.oauth_token) d = datetime.date.today() week_start = d - datetime.timedelta( days=d.weekday()) # round down to last monday search_results = _generate_results_for(city, week_start) if len(search_results) < 2: return {} # Generate image on GCS image_url = weekly_images.build_and_cache_image(city, week_start, search_results) # Generate the weekly text post message = _generate_post_for(city, week_start, search_results) # Can't upload image to FB Page...as the uploaded photo then becomes un-animated # So instead lets link to the image from our FB post # Now post to FB Feed about it post_values = { 'message': message, 'link': image_url, } feed_targeting = get_city_targeting_data(fbl, city) if feed_targeting: # Ideally we'd do this as 'feed_targeting', but Facebook appears to return errors with that due to: # {u'error': {u'message': u'Invalid parameter', u'code': 100, u'is_transient': False, # u'error_user_title': u'Invalid Connection', u'error_subcode': 1487124, u'type': u'FacebookApiException', # u'error_user_msg': u'You can only specify connections to objects you are an administrator or developer of.', # u'error_data': {u'blame_field': u'targeting'}}} post_values['targeting'] = json.dumps(feed_targeting) logging.info("FB Feed Post Values: %s", post_values) endpoint = 'v2.9/%s/feed' % page_id result = fbl.fb.post(endpoint, None, post_values) logging.info('Post Result for %s: %s', city.display_name(), result) return result
def post(self): if self.json_body['scrapinghub_key'] != keys.get('scrapinghub_key'): self.response.status = 403 return fb_uid = '701004' user = users.User.get_by_id(fb_uid) fbl = fb_api.FBLookup(fb_uid, user.fb_access_token) for event_url in self.json_body['events']: logging.info('Adding %s', event_url) event_id = urls.get_event_id_from_url(event_url) if not event_id: logging.warning('Not a valid fb event for adding: %s', event_url) continue fb_event = fbl.get(fb_api.LookupEvent, event_id, allow_cache=False) try: add_entities.add_update_event(fb_event, fbl, creating_method=eventdata.CM_AUTO_WEB) except add_entities.AddEventException: logging.exception('Error adding event %s', event_id)
def create_user(user_id='701004', access_token='Access Token', access_token_expires=None, location='NYC'): fields_str = '%2C'.join(fb_api.OBJ_USER_FIELDS) base_url = '/v2.2/%s' % user_id url = '%s?fields=%s' % (base_url, fields_str) fb_api.FBAPI.results.update({ url: (200, { 'id': user_id, 'name': 'Test User', 'email': '*****@*****.**' }), '%s/events?since=yesterday&fields=id,rsvp_status' % base_url: (200, { "data": {}, }), '%s/friends' % base_url: (200, {}), '%s/permissions' % base_url: (200, {}), }) existing_user = users.User.get_by_id(user_id) assert not existing_user, "Found user: %s" % existing_user if not access_token_expires: access_token_expires = datetime.datetime.now() + datetime.timedelta( days=60) client = 'test' fbl = fb_api.FBLookup(None, None) fb_user = fbl.get(fb_api.LookupUser, user_id) user = user_creation.create_user_with_fbuser(user_id, fb_user, access_token, access_token_expires, location, send_email=True, client=client) return user
def function_migrate_thing_to_new_id(fbapi_obj, old_source_id, new_source_id): old_source = thing_db.Source.get_by_key_name(old_source_id) # Maybe we got two of these and it already ran in parallel, so ignore this one if not old_source: return fbl = fb_api.FBLookup(None, fbapi_obj.access_token_list) fbl.fb.raise_on_page_redirect = True try: results = fbl.get(fb_api.LookupThingCommon, new_source_id) except fb_api.PageRedirectException as e: # If our forwarding address in turn has its own forwarding address, # repoint the old thing further down the chain deferred.defer(function_migrate_thing_to_new_id, fbl.fb, old_source_id, e.to_id) return new_source = thing_db.create_source_from_id(fbl, new_source_id) new_source.creating_fb_uid = new_source.creating_fb_uid or old_source.creating_fb_uid new_source.creation_time = new_source.creation_time or old_source.creation_time new_source.last_scrape_time = new_source.last_scrape_time or old_source.last_scrape_time new_source.num_all_events = (new_source.num_all_events or 0) + (old_source.num_all_events or 0) new_source.num_potential_events = (new_source.num_potential_events or 0) + (old_source.num_potential_events or 0) new_source.num_real_events = (new_source.num_real_events or 0) + (old_source.num_real_events or 0) new_source.num_false_negatives = (new_source.num_false_negatives or 0) + ( old_source.num_false_negatives or 0) # Who has pointers to sources?? migrate_potential_events(old_source_id, new_source_id) new_source.put() old_source.delete()
def handle_alternate_login(self, request): # If the mobile app sent the user to a /....?uid=XX&access_token_md5=YY URL, # then let's verify the parameters, and log the user in as that user if request.get('uid'): if request.get('access_token'): fbl = fb_api.FBLookup(request.get('uid'), request.get('access_token')) fb_user = fbl.get(fb_api.LookupUser, 'me') logging.info("Requested /me with given access_token, got %s", fb_user) if fb_user['profile']['id'] == request.get('uid'): user = users.User.get_by_id(request.get('uid')) access_token_md5 = hashlib.md5( user.fb_access_token).hexdigest() self.set_login_cookie(request.get('uid'), access_token_md5=access_token_md5) if request.get('access_token_md5'): user = users.User.get_by_id(request.get('uid')) if user and request.get('access_token_md5') == hashlib.md5( user.fb_access_token).hexdigest(): # Authenticated! Now save cookie so subsequent requests can trust that this user is authenticated. # The subsequent request will see a valid user_login param (though without an fb_cookie_uid) self.set_login_cookie( request.get('uid'), access_token_md5=self.request.get('access_token_md5')) # But regardless of whether the token was correct, let's redirect and get rid of these url params. current_url_args = {} for arg in sorted(self.request.GET): if arg in ['uid', 'access_token', 'access_token_md5']: continue current_url_args[arg] = self.request.GET.getall(arg) final_url = self.request.path + '?' + urls.urlencode( current_url_args, doseq=True) # Make sure we immediately stop running the initialize() code if we return a URL here return final_url else: return False
def setup_login_state(self, request): #TODO(lambert): change fb api to not request access token, and instead pull it from the user # only request the access token from FB when it's been longer than a day, and do it out-of-band to fetch-and-update-db-and-memcache self.fb_uid = None self.user = None self.access_token = None if len(request.get_all('nt')) > 1: logging.error('Have too many nt= parameters, something is Very Wrong!') for k, v in request.cookies.iteritems(): logging.info("DEBUG: cookie %r = %r", k, v) # Load Facebook cookie try: response = facebook.parse_signed_request_cookie(request.cookies) except Cookie.CookieError: logging.exception("Error processing cookie: %s") return fb_cookie_uid = None if response: fb_cookie_uid = response['user_id'] logging.info("fb cookie id is %s", fb_cookie_uid) # Normally, our trusted source of login id is the FB cookie, # though we may override it below in the case of access_token_md5 trusted_cookie_uid = fb_cookie_uid # for k, v in self.request.cookies.iteritems(): # logging.info('cookie %s = %s', k, v) # Load our dancedeets logged-in user/state our_cookie_uid = None user_login_string = self.get_login_cookie() if user_login_string: user_login_cookie = json.loads(urllib.unquote(user_login_string)) logging.info("Got login cookie: %s", user_login_cookie) if validate_hashed_userlogin(user_login_cookie): our_cookie_uid = user_login_cookie['uid'] # If we have a browser cookie that's verified via access_token_md5, # so let's trust it as authoritative here and ignore the fb cookie if not trusted_cookie_uid and user_login_cookie.get('access_token_md5'): trusted_cookie_uid = our_cookie_uid logging.info("Validated cookie, logging in as %s", our_cookie_uid) if self.request.cookies.get('user_login', ''): logging.info("Deleting old-style user_login cookie") self.response.set_cookie('user_login', '', max_age=0, path='/', domain=self._get_login_cookie_domain()) # If the user has changed facebook users, let's automatically re-login at dancedeets if trusted_cookie_uid and trusted_cookie_uid != our_cookie_uid: self.set_login_cookie(trusted_cookie_uid) our_cookie_uid = trusted_cookie_uid # Don't force-logout the user if there is a our_cookie_uid but not a trusted_cookie_uid # The fb cookie probably expired after a couple hours, and we'd prefer to keep our users logged-in # Logged-out view, just return without setting anything up if not our_cookie_uid: return self.fb_uid = our_cookie_uid self.user = users.User.get_by_id(self.fb_uid) # If we have a user, grab the access token if self.user: if trusted_cookie_uid: # Long-lived tokens should last "around" 60 days, so let's refresh-renew if there's only 40 days left if self.user.fb_access_token_expires: token_expires_soon = (self.user.fb_access_token_expires - datetime.datetime.now()) < datetime.timedelta(days=40) else: # These are either infinite-access tokens (which won't expire soon) # or they are ancient tokens (in which case, our User reload mapreduce has already set user.expired_oauth_token) token_expires_soon = False # Update the access token if necessary if self.user.expired_oauth_token or token_expires_soon or self.request.get('update_fb_access_token'): try: access_token, access_token_expires = self.get_long_lived_token_and_expires(request) except TypeError: logging.info("Could not access cookie ") except facebook.AlreadyHasLongLivedToken: logging.info("Already have long-lived token, FB wouldn't give us a new one, so no need to refresh anything.") else: logging.info("New access token from cookie: %s, expires %s", access_token, access_token_expires) if access_token: self.user = users.User.get_by_id(self.fb_uid) self.user.fb_access_token = access_token self.user.fb_access_token_expires = access_token_expires self.user.expired_oauth_token = False self.user.expired_oauth_token_reason = None # this also sets to memcache self.user.put() logging.info("Stored the new access_token to the User db") else: logging.error("Got a cookie, but no access_token. Using the one from the existing user. Strange!") if 'web' not in self.user.clients: self.user = users.User.get_by_id(self.fb_uid) self.user.clients.append('web') self.user.put() logging.info("Added the web client to the User db") self.access_token = self.user.fb_access_token else: self.access_token = self.user.fb_access_token logging.info("Have dd login cookie but no fb login cookie") if self.user.expired_oauth_token: self.fb_uid = None self.user = None self.access_token = None return elif trusted_cookie_uid: # if we don't have a user but do have a token, the user has granted us permissions, so let's construct the user now try: access_token, access_token_expires = self.get_long_lived_token_and_expires(request) except facebook.AlreadyHasLongLivedToken: logging.warning( "Don't have user, just trusted_cookie_uid. And unable to get long lived token for the incoming request. Giving up and doing logged-out" ) self.fb_uid = None self.access_token = None self.user = None return self.access_token = access_token # Fix this ugly import hack: fbl = fb_api.FBLookup(self.fb_uid, self.access_token) fbl.debug = 'fbl' in self.debug_list fb_user = fbl.get(fb_api.LookupUser, self.fb_uid) referer = self.get_cookie('User-Referer') city = self.request.get('city') or self.get_location_from_headers() or get_location(fb_user) logging.info("User passed in a city of %r, facebook city is %s", self.request.get('city'), get_location(fb_user)) ip = ips.get_remote_ip(self.request) user_creation.create_user_with_fbuser( self.fb_uid, fb_user, self.access_token, access_token_expires, city, ip, send_email=True, referer=referer, client='web' ) # TODO(lambert): handle this MUUUCH better logging.info("Not a /login request and there is no user object, constructed one realllly-quick, and continuing on.") self.user = users.User.get_by_id(self.fb_uid) # Should not happen: if not self.user: logging.error("We still don't have a user!") self.fb_uid = None self.access_token = None self.user = None return else: # no user, no trusted_cookie_uid, but we have fb_uid from the user_login cookie logging.error("We have a user_login cookie, but no user, and no trusted_cookie_uid. Acting as logged-out") self.fb_uid = None self.access_token = None self.user = None return logging.info("Logged in uid %s with name %s and token %s", self.fb_uid, self.user.full_name, self.access_token) # Track last-logged-in state hour_ago = datetime.datetime.now() - datetime.timedelta(hours=1) if not getattr(self.user, 'last_login_time', None) or self.user.last_login_time < hour_ago: # Do this in a separate request so we don't increase latency on this call deferred.defer(update_last_login_time, self.user.fb_uid, datetime.datetime.now(), _queue='slow-queue') backgrounder.load_users([self.fb_uid], allow_cache=False)
def runTest(self): fbl = fb_api.FBLookup('uid', 'access_token') fbl.allow_cache = False # Set up our facebook backend fb_api.FBAPI.results = { URL_111: (200, { 'id': '111', 'name': 'page 1', 'likes': 1 }), '/v2.2/111/feed': (200, { 'data': [] }), '/v2.2/111/events': (200, { 'data': [] }), URL_222: (200, { 'id': '222', 'name': 'page 2', 'likes': 1 }), '/v2.2/222/feed': (200, { 'data': [] }), '/v2.2/222/events': (200, { 'data': [] }), } # Fetch it and construct a source result = fbl.get(fb_api.LookupThingFeed, '111') source = thing_db.create_source_for_id('111', result) source.num_all_events = 5 source.put() source = thing_db.Source.get_by_key_name('111') self.assertEquals(source.name, 'page 1') self.mark_as_error_and_reload(fbl) # Let's verify id 111 no longer exists source = thing_db.Source.get_by_key_name('111') # Now let's load id 222 and verify it exists source = thing_db.Source.get_by_key_name('222') # And verify that our data from the first one got carried over self.assertEquals(source.num_all_events, 5) # But the the remaining data comes from the latest FB values for this page id self.assertEquals(source.name, 'page 2') # Now let's create 111 again, to verify merge works fb_api.FBAPI.results.update({ URL_111: (200, { 'id': '111', 'name': 'page 1', 'likes': 1 }), '/v2.2/111/feed': (200, { 'data': [] }), }) source = thing_db.create_source_for_id('111', result) source.num_all_events = 5 source.put() pe = potential_events.PotentialEvent(key_name="333") #STR_ID_MIGRATE pe.source_ids = [111, 222] pe.source_fields = [ thing_db.GRAPH_TYPE_PROFILE, thing_db.GRAPH_TYPE_PROFILE ] pe.put() self.mark_as_error_and_reload(fbl) pe = potential_events.PotentialEvent.get_by_key_name("333") #STR_ID_MIGRATE self.assertEqual(pe.source_ids, [222]) self.assertEqual(pe.source_fields, [thing_db.GRAPH_TYPE_PROFILE])
def initialize(self, request, response): super(BaseRequestHandler, self).initialize(request, response) self.run_handler = True # Redirect from the bare 'dancedeets.com' to the full 'www.dancedeets.com' url = urlparse.urlsplit(self.request.url) if url.netloc != self._get_full_hostname(): logging.info("Redirecting from %s to %s: %s", url.netloc, self._get_full_hostname(), self.request.url) new_url = urlparse.urlunsplit([ url.scheme, self._get_full_hostname(), url.path, url.query, url.fragment, ]) self.run_handler = False self.redirect(new_url, abort=True) return login_url = self.get_login_url() redirect_url = self.handle_alternate_login(request) if redirect_url: self.run_handler = False # We need to run with abort=False here, or otherwise our set_cookie calls don't work. :( # Reported in https://github.com/GoogleCloudPlatform/webapp2/issues/111 self.redirect(redirect_url, abort=False) return self.setup_login_state(request) self.display['attempt_autologin'] = 1 # If they've expired, and not already on the login page, then be sure we redirect them to there... redirect_for_new_oauth_token = (self.user and self.user.expired_oauth_token) if redirect_for_new_oauth_token: logging.error( "We have a logged in user, but an expired access token. How?!?!" ) # TODO(lambert): delete redirect_for_new_oauth_token codepaths # TODO(lambert): delete codepaths that handle user-id but no self.user. assume this entire thing relates to no-user. if redirect_for_new_oauth_token or ( self.requires_login() and (not self.fb_uid or not self.user)): # If we're getting a referer id and not signed up, save off a cookie until they sign up if not self.fb_uid: logging.info("No facebook cookie.") if not self.user: logging.info("No database user object.") if self.user and self.user.expired_oauth_token: logging.info("User's OAuth token expired") #self.set_cookie('fbsr_' + FACEBOOK_CONFIG['app_id'], '', 'Thu, 01 Jan 1970 00:00:01 GMT') #logging.info("clearing cookie %s", 'fbsr_' + FACEBOOK_CONFIG['app_id']) self.set_cookie( 'User-Message', "You changed your facebook password, so will need to click login again." ) if self.request.get('referer'): self.set_cookie('User-Referer', self.request.get('referer')) if not self.is_login_page(): logging.info("Login required, redirecting to login page: %s", login_url) self.run_handler = False return self.redirect(login_url) else: self.display[ 'attempt_autologin'] = 0 # do not attempt auto-login. wait for them to re-login self.fb_uid = None self.access_token = None self.user = None # If they have a fb_uid, let's do lookups on that behalf (does not require a user) if self.fb_uid: allow_cache = bool(int(self.request.get('allow_cache', 1))) self.fbl = fb_api.FBLookup(self.fb_uid, self.access_token) self.fbl.allow_cache = allow_cache # Always look up the user's information for every page view...? self.fbl.request(fb_api.LookupUser, self.fb_uid) else: self.fbl = fb_api.FBLookup(None, None) self.fbl.debug = 'fbl' in self.debug_list if self.user: self.jinja_env.filters[ 'date_only_human_format'] = self.user.date_only_human_format self.jinja_env.filters[ 'date_human_format'] = self.user.date_human_format self.jinja_env.filters[ 'time_human_format'] = self.user.time_human_format self.jinja_env.globals[ 'duration_human_format'] = self.user.duration_human_format self.display['messages'] = self.user.get_and_purge_messages() else: self.jinja_env.filters[ 'date_only_human_format'] = dates.date_only_human_format self.jinja_env.filters[ 'date_human_format'] = dates.date_human_format self.jinja_env.filters[ 'time_human_format'] = dates.time_human_format self.jinja_env.globals[ 'duration_human_format'] = dates.duration_human_format self.display['login_url'] = login_url self.jinja_env.filters['datetime_format'] = dates.datetime_format self.jinja_env.globals['dd_event_url'] = urls.dd_event_url self.jinja_env.globals['raw_fb_event_url'] = urls.raw_fb_event_url self.jinja_env.globals['dd_admin_event_url'] = urls.dd_admin_event_url self.jinja_env.globals[ 'dd_admin_source_url'] = urls.dd_admin_source_url self.display['request'] = request self.display['app_id'] = facebook.FACEBOOK_CONFIG['app_id'] self.display['prod_mode'] = self.request.app.prod_mode self.display[ 'base_hostname'] = 'dancedeets.com' if self.request.app.prod_mode else 'dev.dancedeets.com' self.display['full_hostname'] = self._get_full_hostname() self.display['email_suffix'] = '' self.display['keyword_tokens'] = [{ 'value': x.public_name } for x in event_types.STYLES] fb_permissions = 'rsvp_event,email,user_events' if self.request.get('all_access'): fb_permissions += ',read_friendlists,manage_pages' self.display['fb_permissions'] = fb_permissions already_used_mobile = self.user and ( 'react-android' in self.user.clients or 'react-ios' in self.user.clients or 'android' in self.user.clients or 'ios' in self.user.clients or False) mobile_platform = mobile.get_mobile_platform(self.request.user_agent) show_mobile_promo = not mobile_platform and not already_used_mobile self.display['show_mobile_promo'] = show_mobile_promo self.display['mobile_platform'] = mobile_platform if mobile_platform == mobile.MOBILE_ANDROID: self.display['mobile_app_url'] = mobile.ANDROID_URL elif mobile_platform == mobile.MOBILE_IOS: self.display['mobile_app_url'] = mobile.IOS_URL self.display['mobile'] = mobile self.display['mobile_show_smartbanner'] = True self.display['ip_location'] = self.get_location_from_headers() self.display['styles'] = event_types.STYLES self.display['us_cities'] = [ 'New York, NY', 'Los Angeles, CA', 'San Francisco, CA', '', 'Anaheim, CA', 'Boston, MA', 'Chicago, IL', 'Detroit, MI', 'Las Vegas, CA', 'Montreal, Canada', 'Ottawa, Canada', 'Philadelphia, PA', 'Phoenix, AZ', 'Portland, OR', 'Sacramento, CA', 'San Diego, CA', 'Seattle, WA', 'Toronto, Canada', 'Vancouver, Canada', 'Washington, DC', ] self.display['eu_cities'] = [ 'Amsterdam, Netherlands', 'Barcelona, Spain', 'Berlin, Germany', 'Bratislava, Slovakia', 'Brno, Czech Republic', 'Brussels, Belgium', 'Copenhagen, Denmark', 'Frankfurt, Germany', 'Geneva, Switzerland', 'Helsinki, Finland', 'London, UK', 'Lyon, France', 'Manchester, United Kingdom', 'Marseille, France', 'Milan, Italy', 'Oslo, Norway', 'Paris, France', 'Rome, Italy', 'Stockholm, Sweden', 'Vienna, Austria', 'Warsaw, Poland', 'Zurich, Switzerland', ] self.display['other'] = [ 'Argentina', 'Australia', 'Brasil: Minas Gerais', 'Colombia', 'Hong Kong', 'India', 'Japan: Osaka', 'Japan: Tokyo', 'Malaysia', 'New Zealand', 'Peru', 'Philippines', 'Singapore', 'Taiwan', ] self.display['deb'] = self.request.get('deb') self.display['debug_list'] = self.debug_list self.display['user'] = self.user webview = bool(request.get('webview')) self.display['webview'] = webview if webview: if bool(request.get('nd', 1)): self.display['class_base_template'] = '_new_base_webview.html' else: self.display['class_base_template'] = '_base_webview.html' else: if bool(request.get('nd', 1)): self.display['class_base_template'] = '_new_base.html' else: self.display['class_base_template'] = '_base.html' self.display.update(rankings.retrieve_summary())
def setUp(self): super(TestClassifier, self).setUp() self.fbl = fb_api.FBLookup("dummyid", None)
def facebook_post(auth_token, db_event): link = campaign_url(db_event.id, 'fb_feed') datetime_string = db_event.start_time.strftime('%s @ %s' % (DATE_FORMAT, TIME_FORMAT)) page_id = auth_token.token_nickname endpoint = 'v2.5/%s/feed' % page_id fbl = fb_api.FBLookup(None, auth_token.oauth_token) post_values = {} # post_values['message'] = db_event.name post_values['link'] = link post_values['name'] = db_event.name post_values['caption'] = datetime_string name = _get_posting_user(db_event) human_date = db_event.start_time.strftime('%B %-d') # TODO: Sometimes we definitely know the City (from a lat/long), but FB doesn't give us a city. # Hopefully in the Great Event Location Cleanup, can take care of this... if db_event.city: location = '%s ' % db_event.city else: location = '' host = '' admins = db_event.admins if admins: admin_ids = [x['id'] for x in admins] page_admin_ids = fb_api_util.filter_by_type(fbl, admin_ids, 'page') host = text.human_list('@[%s]' % x for x in page_admin_ids) # Tag it if we can if db_event.venue.get('id'): venue = '@[%s]' % db_event.venue.get('id') else: venue = db_event.location_name message = "Hey %sdancers, time to dance! New dance event on %s at %s." % (location, human_date, venue) if host and host != venue: message += ' Hosted by our friends at %s.' % host if name: message += ' Thanks to %s for adding it to DanceDeets!' % name post_values['message'] = message description = db_event.description if len(description) > 10000: post_values['description'] = description[:9999] + u"…" else: post_values['description'] = description post_values['description'] = post_values['description'] cover = db_event.largest_cover if cover: post_values['picture'] = cover['source'] venue_id = db_event.venue.get('id') if venue_id: post_values['place'] = venue_id feed_targeting = get_targeting_data(fbl, db_event) if feed_targeting: # Ideally we'd do this as 'feed_targeting', but Facebook appears to return errors with that due to: # {u'error': {u'message': u'Invalid parameter', u'code': 100, u'is_transient': False, # u'error_user_title': u'Invalid Connection', u'error_subcode': 1487124, u'type': u'FacebookApiException', # u'error_user_msg': u'You can only specify connections to objects you are an administrator or developer of.', # u'error_data': {u'blame_field': u'targeting'}}} post_values['targeting'] = json.dumps(feed_targeting) logging.info("FB Feed Post Values: %s", post_values) return fbl.fb.post(endpoint, None, post_values)
def facebook_post(auth_token, db_event): link = common.campaign_url(db_event, 'fb_feed') datetime_string = db_event.start_time.strftime( '%s @ %s' % (common.DATE_FORMAT, common.TIME_FORMAT)) page_id = auth_token.token_nickname endpoint = 'v2.9/%s/feed' % page_id fbl = fb_api.FBLookup(None, auth_token.oauth_token) post_values = {} # post_values['message'] = db_event.name post_values['link'] = link post_values['name'] = db_event.name post_values['caption'] = datetime_string name = _get_posting_user(db_event) human_date = db_event.start_time.strftime('%B %-d') # TODO: Sometimes we definitely know the City (from a lat/long), but FB doesn't give us a city. # Hopefully in the Great Event Location Cleanup, can take care of this... if db_event.city: location = db_event.city else: location = '' host = '' admins = db_event.admins if admins: admin_ids = [x['id'] for x in admins] page_admin_ids = fb_api_util.filter_by_type(fbl, admin_ids, 'page') # TODO: Can I @mention the people here too, like I do as a human? Or does it only work with pages? host = text.human_list('@[%s]' % x for x in page_admin_ids) # Tag it if we can if db_event.venue_id: venue = '@[%s]' % db_event.venue_id else: venue = db_event.location_name if not location: # Don't want to post events globally...too noisy return {} params = { 'location': location, 'date': human_date, 'venue': venue, } messages = [ 'Dancers, are you ready? %(venue)s has an event on %(date)s in %(location)s.', 'Hello %(location)s dancers, mark your calendars! We just found a new dance event on %(date)s at %(venue)s.', 'Hey %(location)s dancers, save the date! Look what we found coming up on %(date)s at %(venue)s.', 'Just posted! We have an upcoming dance event on %(date)s at %(venue)s in %(location)s.', 'What\'s up %(location)s, there\'s a dance event at %(venue)s on %(date)s.', ] message = random.choice(messages) % params if host and host != venue: message += random.choice([ ' Hosted by our friends at %(host)s.', ' Thanks to our buddies at %(host)s for hosting!', ' Hitup the awesome %(host)s with any questions you\'ve got!', ]) % { 'host': host } if name: message += random.choice([ ' Thanks to %(name)s for adding it to DanceDeets!', ' And a special thanks to %(name)s, for sharing it with you all on DanceDeets!', ' This event brought to you on DanceDeets courtesy of %(name)s!', ]) % { 'name': name } post_values['message'] = message description = db_event.description if len(description) > 10000: post_values['description'] = description[:9999] + u"…" else: post_values['description'] = description post_values['description'] = post_values['description'] cover = db_event.largest_cover if cover: post_values['picture'] = cover['source'] venue_id = db_event.venue_id if venue_id: post_values['place'] = venue_id feed_targeting = get_targeting_data(fbl, db_event) if feed_targeting: # Ideally we'd do this as 'feed_targeting', but Facebook appears to return errors with that due to: # {u'error': {u'message': u'Invalid parameter', u'code': 100, u'is_transient': False, # u'error_user_title': u'Invalid Connection', u'error_subcode': 1487124, u'type': u'FacebookApiException', # u'error_user_msg': u'You can only specify connections to objects you are an administrator or developer of.', # u'error_data': {u'blame_field': u'targeting'}}} post_values['targeting'] = json.dumps(feed_targeting) logging.info("FB Feed Post Values: %s", post_values) return fbl.fb.post(endpoint, None, post_values)
def runTest(self): fbl = fb_api.FBLookup('uid', 'access_token') fields_str = '%2C'.join(fb_api.OBJ_USER_FIELDS) url = '/v2.9/uid?fields=%s' % fields_str event_url = '/v2.9/uid/events?since=yesterday&fields=id,rsvp_status&limit=3000' # Set up our facebook backend fb_api.FBAPI.results = { url: (200, {}), event_url: (200, {}), '/v2.9/uid/friends': (200, {}), '/v2.9/uid/permissions': (200, {}), } # And fetching it then populates our memcache and db result = fbl.get(fb_api.LookupUser, 'uid') self.assertEqual( result, { 'empty': None, 'friends': {}, 'permissions': {}, 'profile': {}, 'rsvp_for_future_events': {}, }) # Now remove our facebook backend, and test all our caches fb_api.FBAPI.results = {} fbl.clear_local_cache() # Check that if allow_cache=False, we cannot fetch anything fbl.allow_cache = False self.assertRaises(fb_api.NoFetchedDataException, fbl.get, fb_api.LookupUser, 'uid') fbl.allow_cache = True # Rely on memcache/dbcache to fulfill this request now fbl.clear_local_cache() result = fbl.get(fb_api.LookupUser, 'uid') self.assertEqual( result, { 'empty': None, 'friends': {}, 'permissions': {}, 'profile': {}, 'rsvp_for_future_events': {}, }) # Clear memcache... user_key = (fb_api.LookupUser, '"uid"') fbl.m.invalidate_keys([user_key]) fbl.clear_local_cache() # Check that fetching with allow_db_cache=False, fails fbl.allow_dbcache = False self.assertRaises(fb_api.NoFetchedDataException, fbl.get, fb_api.LookupUser, 'uid') fbl.allow_dbcache = True # But allowing db cache still works (and repopulates memcache) result = fbl.get(fb_api.LookupUser, 'uid') self.assertEqual( result, { 'empty': None, 'friends': {}, 'permissions': {}, 'profile': {}, 'rsvp_for_future_events': {}, }) # Clear dbcache, but still can work (because of memcache) fbl.db.invalidate_keys([user_key]) fbl.clear_local_cache() # Without allowing memcache read, it fails fbl.allow_memcache_read = False self.assertRaises(fb_api.NoFetchedDataException, fbl.get, fb_api.LookupUser, 'uid') fbl.allow_memcache_read = True # But with memcache read, it works fine result = fbl.get(fb_api.LookupUser, 'uid') self.assertEqual( result, { 'empty': None, 'friends': {}, 'permissions': {}, 'profile': {}, 'rsvp_for_future_events': {}, }) # Clear memcache, now that db is empty, data is entirely gone, and it no longer works fbl.m.invalidate_keys([user_key]) fbl.clear_local_cache() self.assertRaises(fb_api.NoFetchedDataException, fbl.get, fb_api.LookupUser, 'uid')
def runTest(self): fbl = fb_api.FBLookup('uid', 'access_token') fbl.allow_cache = False # Set up our facebook backend fields_str = '%2C'.join(fb_api.OBJ_EVENT_FIELDS) url = '/v2.9/eid?fields=%s' % fields_str picture_url = '/v2.9/eid/picture?redirect=false&type=large' # Inaccessible event fb_api.FBAPI.results = { url: (400, { "error": { "message": "Unsupported get request.", "type": "GraphMethodException", "code": 100 } }), picture_url: (400, { "error": { "message": "Unsupported get request.", "type": "GraphMethodException", "code": 100 } }), } result = fbl.get(fb_api.LookupEvent, 'eid') self.assertEqual(result['empty'], fb_api.EMPTY_CAUSE_INSUFFICIENT_PERMISSIONS) fbl.clear_local_cache() # Partial timeout of optional field fb_api.FBAPI.results = { url: (200, { 'id': 'eid' }), '/?fields=images&ids=%7Bresult%3Dinfo%3A%24.cover.id%7D': fb_api_stub.RESULT_TIMEOUT, picture_url: (200, {}), } result = fbl.get(fb_api.LookupEvent, 'eid') self.assertEqual(result['info']['id'], 'eid') fbl.clear_local_cache() # Partial timeout of required field fb_api.FBAPI.results = { url: (200, { 'id': 'eid' }), '/?fields=images&ids=%7Bresult%3Dinfo%3A%24.cover.id%7D': fb_api_stub.RESULT_TIMEOUT, picture_url: fb_api_stub.RESULT_TIMEOUT, } self.assertRaises(fb_api.NoFetchedDataException, fbl.get, fb_api.LookupEvent, 'eid') fbl.clear_local_cache() # Event without a Cover field fb_api.FBAPI.results = { url: (200, { "name": "Event Title", "start_time": "2014-07-12T17:00:00-0400", "id": "eid" }), '/?fields=images&ids=%7Bresult%3Dinfo%3A%24.cover.id%7D': (400, { 'error': { 'message': 'Cannot specify an empty identifier', 'code': 2500, 'type': 'OAuthException' } }), picture_url: (200, { "data": [{ "pic": "", "all_members_count": 437, }] }), } result = fbl.get(fb_api.LookupEvent, 'eid') self.assertEqual(result['empty'], None) self.assertEqual(result['info']['id'], 'eid') fbl.clear_local_cache() fb_api.FBAPI.do_timeout = True self.assertRaises(fb_api.NoFetchedDataException, fbl.get, fb_api.LookupEvent, 'eid') fb_api.FBAPI.do_timeout = False fbl.clear_local_cache()
def initialize(self, request, response): super(BaseRequestHandler, self).initialize(request, response) self.run_handler = True if abuse.is_abuse(self.request): self.run_handler = False self.response.out.write( 'You are destroying our server with your request rate. Please implement rate-limiting, respect robots.txt, and/or email [email protected]' ) return # Redirect from the bare 'dancedeets.com' to the full 'www.dancedeets.com' url = urlparse.urlsplit(self.request.url) # We technically don't need dd.events in here, since its handler is a BareBonesRequestHandler...but it include it to be safe. allowed_passthrough_domains = [r'dev\.dancedeets\.com$', r'img\.dancedeets\.com$', r'dd\.events$', r'dancer?\.bio$'] matches_passthrough_domain = [x for x in allowed_passthrough_domains if re.search(x, url.netloc)] if not os.environ.get('DEBUG_MEMORY_LEAKS') and url.netloc != self._get_full_hostname() and not matches_passthrough_domain: logging.info("Redirecting from %s to %s: %s", url.netloc, self._get_full_hostname(), self.request.url) new_url = urlparse.urlunsplit([ url.scheme, self._get_full_hostname(), url.path, url.query, url.fragment, ]) self.run_handler = False self.redirect(new_url, abort=True) return # Always turn https on! For now, let's use a short expiry # This only 'takes effect' when it is returned on an https domain, # so we still need to make sure to add an https redirect. https_redirect_duration = 60 * 60 * 24 * 7 if url.netloc != 'dev.dancedeets.com': self.response.headers.add_header('Strict-Transport-Security', 'max-age=%s' % https_redirect_duration) # This is how we detect if the incoming url is on https in GAE Flex (we cannot trust request.url) if request.method == 'GET' and request.environ.get('HTTP_X_FORWARDED_PROTO') == 'http': new_url = urlparse.urlunsplit([ 'https', url.netloc, url.path, url.query, url.fragment, ]) self.run_handler = False self.redirect(new_url, abort=True) login_url = self.get_login_url() redirect_url = self.handle_alternate_login(request) if redirect_url: self.run_handler = False # We need to run with abort=False here, or otherwise our set_cookie calls don't work. :( # Reported in https://github.com/GoogleCloudPlatform/webapp2/issues/111 self.redirect(redirect_url, abort=False) return self.setup_login_state(request) self.display['attempt_autologin'] = 1 # If they've expired, and not already on the login page, then be sure we redirect them to there... redirect_for_new_oauth_token = (self.user and self.user.expired_oauth_token) if redirect_for_new_oauth_token: logging.error("We have a logged in user, but an expired access token. How?!?!") # TODO(lambert): delete redirect_for_new_oauth_token codepaths # TODO(lambert): delete codepaths that handle user-id but no self.user. assume this entire thing relates to no-user. if redirect_for_new_oauth_token or (self.requires_login() and (not self.fb_uid or not self.user)): # If we're getting a referer id and not signed up, save off a cookie until they sign up if not self.fb_uid: logging.info("No facebook cookie.") if not self.user: logging.info("No database user object.") if self.user and self.user.expired_oauth_token: logging.info("User's OAuth token expired") #self.set_cookie('fbsr_' + FACEBOOK_CONFIG['app_id'], '', 'Thu, 01 Jan 1970 00:00:01 GMT') #logging.info("clearing cookie %s", 'fbsr_' + FACEBOOK_CONFIG['app_id']) self.set_cookie('User-Message', "You changed your facebook password, so will need to click login again.") if self.request.get('referer'): self.set_cookie('User-Referer', self.request.get('referer')) if not self.is_login_page(): logging.info("Login required, redirecting to login page: %s", login_url) self.run_handler = False return self.redirect(login_url) else: self.display['attempt_autologin'] = 0 # do not attempt auto-login. wait for them to re-login self.fb_uid = None self.access_token = None self.user = None # If they have a fb_uid, let's do lookups on that behalf (does not require a user) if self.fb_uid: self.setup_fbl() # Always look up the user's information for every page view...? self.fbl.request(fb_api.LookupUser, self.fb_uid) else: self.fbl = fb_api.FBLookup(None, None) self.fbl.debug = 'fbl' in self.debug_list if self.user: self.jinja_env.filters['date_only_human_format'] = self.user.date_only_human_format self.jinja_env.filters['date_human_format'] = self.user.date_human_format self.jinja_env.filters['time_human_format'] = self.user.time_human_format self.jinja_env.globals['duration_human_format'] = self.user.duration_human_format self.display['messages'] = self.user.get_and_purge_messages() else: self.jinja_env.filters['date_only_human_format'] = dates.date_only_human_format self.jinja_env.filters['date_human_format'] = dates.date_human_format self.jinja_env.filters['time_human_format'] = dates.time_human_format self.jinja_env.globals['duration_human_format'] = dates.duration_human_format self.display['login_url'] = login_url self.jinja_env.filters['datetime_format'] = dates.datetime_format self.jinja_env.globals['dd_event_url'] = urls.dd_event_url self.jinja_env.globals['raw_fb_event_url'] = urls.raw_fb_event_url self.jinja_env.globals['dd_admin_event_url'] = urls.dd_admin_event_url self.jinja_env.globals['dd_admin_source_url'] = urls.dd_admin_source_url locales = self.request.headers.get('Accept-Language', '').split(',') self.locales = [x.split(';')[0] for x in locales] if self.request.get('hl'): self.locales = self.request.get('hl').split(',') logging.info('Accept-Language is %s, final locales are %s', self.request.headers.get('Accept-Language', ''), self.locales) self.display['request'] = request self.display['app_id'] = facebook.FACEBOOK_CONFIG['app_id'] self.display['prod_mode'] = self.request.app.prod_mode self.display['base_hostname'] = 'dancedeets.com' if self.request.app.prod_mode else 'dev.dancedeets.com' self.display['full_hostname'] = self._get_full_hostname() self.display['email_suffix'] = '' self.display['keyword_tokens'] = [{'value': x.public_name} for x in event_types.STYLES] fb_permissions = 'rsvp_event,email,user_events' if self.request.get('all_access'): fb_permissions += ',read_friendlists,manage_pages' self.display['fb_permissions'] = fb_permissions already_used_mobile = self.user and ( 'react-android' in self.user.clients or 'react-ios' in self.user.clients or 'android' in self.user.clients or 'ios' in self.user.clients or False ) mobile_platform = mobile.get_mobile_platform(self.request.user_agent) show_mobile_promo = not mobile_platform and not already_used_mobile self.display['show_mobile_promo'] = show_mobile_promo self.display['mobile_platform'] = mobile_platform if mobile_platform == mobile.MOBILE_ANDROID: self.display['mobile_app_url'] = mobile.ANDROID_URL elif mobile_platform == mobile.MOBILE_IOS: self.display['mobile_app_url'] = mobile.IOS_URL self.display['mobile'] = mobile self.display['mobile_show_smartbanner'] = True import time start = time.time() self.display['ip_location'] = self.get_location_from_headers() timelog.log_time_since('Getting City from IP', start) self.display['styles'] = event_types.STYLES self.display['cities'] = [( 'North America', [ 'Albuquerque', 'Austin', 'Baltimore', 'Boston', 'Chicago', 'Detroit', 'Houston', 'Las Vegas', 'Los Angeles', 'Miami', 'New York City', 'Orlando', 'Philadelphia', 'Portland', 'San Francisco', 'San Jose', 'San Diego', 'Seattle', 'Washington DC', '', 'Calgary', 'Edmonton', 'Montreal', 'Ottawa', 'Toronto', 'Vancouver', '' 'Mexico: Mexico City', ] ), ( 'Latin/South America', [ 'Argentina: Buenos Aires', 'Argentina: Neuquen', 'Brazil: Belo Horizonte', 'Brazil: Brasilia', 'Brazil: Cruitiba', 'Brazil: Porto Alegre', 'Brazil: Rio de Janeiro', 'Brazil: Sao Paulo', 'Colombia', 'Chile: Santiago', 'Peru: Lima', ] ), ( 'Europe', [ 'Austria: Vienna', 'Belgium: Brussels', 'Czech: Prague Republic', 'Denmark: Copenhagen', 'Estonia: Tallinn', 'Finland: Helsinki', 'France: Nantes', 'France: Paris', 'France: Perpignan', 'Germany: Berlin', 'Germany: Hamburg', u'Germany: Köln/Cologne', 'Germany: Leipzig', u'Germany: München/Munich', 'Italy: Milan', 'Italy: Rome', 'Netherlands: Amsterdam', 'Norway: Oslo', 'Poland: Warsaw', 'Poland: Wroclaw', 'Russia: Moscow', 'Slovakia: Bratislava', 'Spain: Barcelona', 'Sweden: Malmoe', 'Sweden: Stockholm', 'Switzerland: Basel', 'Switzerland: Geneve', 'Switzerland: Zurich', 'United Kingdom: Leeds', 'United Kingdom: London', ] ), ( 'Asia', [ 'Hong Kong', 'India', u'Japan: Tokyo (日本東京)', u'Japan: Osaka (日本大阪)', 'Korea', u'Taiwan: Kaohsiung (台灣高雄市)', u'Taiwan: Taipei (台灣台北市)', u'Taiwan: Taichung (台灣臺中市)', 'Philippines', 'Singapore', 'Australia: Melbourne', 'Australia: Perth', 'Australia: Sydney', ] )] self.display['deb'] = self.request.get('deb') self.display['debug_list'] = self.debug_list self.display['user'] = self.user webview = bool(request.get('webview')) self.display['webview'] = webview if webview: self.display['class_base_template'] = '_new_base_webview.html' else: self.display['class_base_template'] = '_new_base.html' totals = rankings.retrieve_summary() totals['total_events'] = humanize.intcomma(totals['total_events']) totals['total_users'] = humanize.intcomma(totals['total_users']) self.display.update(totals)
def get_fblookup(self): fbl = fb_api.FBLookup(self.fb_uid, self.fb_access_token) return fbl
def runTest(self): fbl = fb_api.FBLookup('uid', 'access_token') fbl.allow_cache = False # Set up our facebook backend fb_api.FBAPI.results = { URL_111: (200, { 'id': '111', 'name': 'page 1' }), URL_111_FEED: (200, { 'data': [] }), URL_111_EVENTS: (200, { 'data': [] }), URL_111_INFO2: (200, {}), URL_222: (200, { 'id': '222', 'name': 'page 2' }), URL_222_FEED: (200, { 'data': [] }), URL_222_EVENTS: (200, { 'data': [] }), URL_222_INFO2: (200, {}), '/%s/111?metadata=1' % fb_api.LookupThingCommon.version: (200, { 'metadata': { 'type': 'page' } }), '/%s/222?metadata=1' % fb_api.LookupThingCommon.version: (200, { 'metadata': { 'type': 'page' } }), } # Fetch it and construct a source source = thing_db.create_source_from_id(fbl, '111') source.num_all_events = 5 source.put() source = thing_db.Source.get_by_key_name('111') self.assertEquals(source.name, 'page 1') self.mark_as_error_and_reload(fbl) # Let's verify id 111 no longer exists source = thing_db.Source.get_by_key_name('111') # Now let's load id 222 and verify it exists source = thing_db.Source.get_by_key_name('222') # And verify that our data from the first one got carried over self.assertEquals(source.num_all_events, 5) # But the the remaining data comes from the latest FB values for this page id self.assertEquals(source.name, 'page 2') # Now let's create 111 again, to verify merge works fb_api.FBAPI.results.update({ URL_111: (200, { 'id': '111', 'name': 'page 1' }), URL_111_FEED: (200, { 'data': [] }), }) source = thing_db.create_source_from_id(fbl, '111') source.num_all_events = 5 source.put() pe = potential_events.PotentialEvent(key_name="333") pe.set_sources([potential_events.PESource("111", thing_db.FIELD_FEED), potential_events.PESource("222", thing_db.FIELD_FEED)]) pe.put() self.mark_as_error_and_reload(fbl) pe = potential_events.PotentialEvent.get_by_key_name("333") #STR_ID_MIGRATE self.assertEqual(pe.sources(), [potential_events.PESource("222", thing_db.FIELD_FEED)])
def get(self, name): topics = topic_db.Topic.query(topic_db.Topic.url_path == name).fetch(1) if not topics: self.response.set_status(404) return topic = topics[0] if topic.graph_id: # We shouldn't need any tokens to access pages fbl = fb_api.FBLookup(None, None) fb_source = fbl.get(topic_db.LookupTopicPage, topic.graph_id) else: fb_source = None def prefilter(doc_event): """Function for fitlering doc results, before we spend the energy to load the corresponding DBEvents. We only want on-topic events here: - Must contain keyword in the title - Must contain keyword on a line where it makes up >10% of the text (for judges, workshops, etc). We want to hide the resume-includes-classes-from-X people """ logging.info("Prefiltering event %s", doc_event.doc_id) name = doc_event.field('name').value.lower() description = doc_event.field('description').value.lower() description_lines = description.split('\n') for keyword in topic.search_keywords: keyword_word_re = re.compile(r'\b%s\b' % keyword) if keyword_word_re.search(name): return True for line in description_lines: result = keyword_word_re.search(line) # If the keyword is more than 10% of the text in the line: # Examples: # "- HOUSE - KAPELA (Serial Stepperz/Wanted Posse)" # "5th November : EVENT Judged by HIRO :" if result: if 1.0 * len(keyword) / len(line) > 0.1: return True else: logging.info( "Found keyword %r on line, but not long enough: %r", keyword, line) logging.info("Prefilter dropping event %s with name: %r" % (doc_event.doc_id, name)) return False keywords = ' OR '.join('"%s"' % x for x in topic.search_keywords) search_query = search_base.SearchQuery(keywords=keywords) # Need these fields for the prefilter search_query.extra_fields = ['name', 'description'] search_results = search.Search(search_query).get_search_results( prefilter=prefilter) self.display['topic_title'] = topic.override_title or ( fb_source and fb_source['info']['name']) self.display['topic_image'] = topic.override_image or ( fb_source and fb_source['picture']['data']['url']) self.display['topic_description'] = topic.override_description or ( fb_source and fb_source['info'].get('about')) or '' self.display['all_results'] = search_results by_year = [] for year, month_events in sorted( grouping.group_results_by_date(search_results).items()): by_year.append((year, sorted(month_events.items()))) self.display['group_by_date'] = by_year by_country = sorted( grouping.group_results_by_location(search_results).items(), key=lambda x: (-len(x[1]), x[0])) self.display['group_by_location'] = by_country # TODO: # show points on map (future and past?) # show future events # show past events # show high quality and low quality events (most viable with 'past') # have an ajax filter on the page that lets me filter by location? self.display['fb_page'] = fb_source self.render_template('topic')
def load_potential_events_for_user(user): fbl = fb_api.FBLookup(user.fb_uid, user.fb_access_token) fbl.allow_cache = False load_potential_events_for_user_ids(fbl, [user.fb_uid])
def runTest(self): ids = ['110312662362915'] fbl = fb_api.FBLookup(None, None) page_ids = fb_api_util.filter_by_type(fbl, ids, 'page') self.assertEqual(page_ids, ids)
def setUp(self): super(TestEventLocations, self).setUp() self.fbl = fb_api.FBLookup("dummyid", None)