def user_from_facebook_auth_response(auth_response, initial_user=None, is_test=False): if 'accessToken' in auth_response: facebook_access_token = auth_response['accessToken'] else: facebook_access_token = auth_response fb_user = fb_user_from_facebook_access_token(facebook_access_token) facebook_id = fb_user['id'] try: linked_facebook = LinkedFacebookAccount.objects.filter(facebook_id=facebook_id).select_related( 'user__profile').first() if not linked_facebook: raise LinkedFacebookAccount.DoesNotExist() save_linked_facebook(linked_facebook.user, facebook_access_token, fb_user, linked_facebook=linked_facebook) user = linked_facebook.user location = initial_user and initial_user.get('location') if location: location_controller.update_profile_location(user.ap, location) except LinkedFacebookAccount.DoesNotExist: debug_logger.debug('LinkedFacebookAccount.DoesNotExist for facebook_id %s' % facebook_id) if 'email' not in fb_user: dev_msg = 'Facebook user has no email: %s' % json.dumps(fb_user) debug_logger.error(dev_msg) raise ShoutitBadRequest(message=FB_LINK_ERROR_EMAIL, developer_message=dev_msg) user = user_controller.auth_with_facebook(fb_user, initial_user, is_test) try: save_linked_facebook(user, facebook_access_token, fb_user) except (ValidationError, IntegrityError) as e: raise ShoutitBadRequest(message=FB_LINK_ERROR_TRY_AGAIN, developer_message=str(e)) return user
def delete_linked_facebook_account(facebook_user_id): try: la = LinkedFacebookAccount.objects.get(facebook_id=facebook_user_id) except LinkedFacebookAccount.DoesNotExist: debug_logger.error("LinkedFacebookAccount for facebook id: %s does not exist" % facebook_user_id) else: # Delete LinkedFacebookAccount user = la.user la.delete() # Send `profile_update` on Pusher notifications_controller.notify_user_of_profile_update(user)
def facebook_graph_object(graph_path, params): graph_url = FB_GRAPH_URL + graph_path try: response = requests.get(graph_url, params=params, timeout=20) response_data = response.json() error = response_data.get('error') if response.status_code != 200 or error: dev_msg = error.get('message') if isinstance(error, dict) else str(response_data) dev_msg = "Facebook Graph error: %s" % dev_msg raise ShoutitBadRequest(message=FB_ERROR_TRY_AGAIN, developer_message=dev_msg) return response_data except requests.RequestException as e: dev_msg = "Facebook Graph error: %s" % str(e) debug_logger.error(dev_msg) raise ShoutitBadRequest(message=FB_ERROR_TRY_AGAIN, developer_message=dev_msg)
def update_linked_facebook_account_scopes(facebook_user_id): try: la = LinkedFacebookAccount.objects.get(facebook_id=facebook_user_id) except LinkedFacebookAccount.DoesNotExist: debug_logger.error("LinkedFacebookAccount for facebook id: %s does not exist" % facebook_user_id) else: try: token_data = debug_token(la.access_token) except ShoutitBadRequest: la.delete() debug_logger.error("LinkedFacebookAccount for facebook id: %s is expired. Deleting it" % facebook_user_id) else: scopes = token_data['scopes'] la.scopes = scopes la.save(update_fields=['scopes']) # Send `profile_update` on Pusher notifications_controller.notify_user_of_profile_update(la.user)
def extend_token(short_lived_token): exchange_url = FB_GRAPH_ACCESS_TOKEN_URL params = { 'client_id': settings.FACEBOOK_APP_ID, 'client_secret': settings.FACEBOOK_APP_SECRET, 'grant_type': "fb_exchange_token", 'fb_exchange_token': short_lived_token } try: response = requests.get(exchange_url, params=params, timeout=20) if response.status_code != 200: raise ValueError("Invalid access token: %s" % response.content) response_params = dict(urlparse.parse_qsl(response.content)) access_token = response_params.get('access_token') if not access_token: raise ValueError('`access_token` not in response: %s' % response.content) expires = response_params.get('expires') # Sometimes Facebook doesn't return expiry, assume 60 days response_params['expires'] = expires or SIXTY_DAYS except (requests.RequestException, ValueError) as e: debug_logger.error("Facebook token extend error: %s" % str(e)) raise ShoutitBadRequest(message=FB_ERROR_TRY_AGAIN, developer_message=str(e)) return response_params
def link_facebook_account(user, facebook_access_token): """ Add LinkedFacebookAccount to user """ fb_user = fb_user_from_facebook_access_token(facebook_access_token) facebook_id = fb_user['id'] linked_page_ids = [] # Check whether the Facebook account is already linked try: la = LinkedFacebookAccount.objects.get(facebook_id=facebook_id) debug_logger.warning('User %s tried to link already linked facebook account id: %s.' % (user, facebook_id)) if la.user != user: raise ShoutitBadRequest(_("Facebook account is already linked to somebody else's profile")) linked_page_ids = list(la.pages.values_list('facebook_id', flat=True)) # copy the list except LinkedFacebookAccount.DoesNotExist: pass # Unlink previous Facebook account unlink_facebook_user(user, strict=False) # Link Facebook account try: linked_facebook = save_linked_facebook(user, facebook_access_token, fb_user) except (ValidationError, IntegrityError) as e: debug_logger.error("LinkedFacebookAccount creation error: %s" % str(e)) raise ShoutitBadRequest(message=FB_LINK_ERROR_TRY_AGAIN, developer_message=str(e)) # Link Facebook Pages if any existed in the previous LinkedFacebookAccount for facebook_page_id in linked_page_ids: link_facebook_page(linked_facebook, facebook_page_id) # Activate the user if not yet activated if not user.is_activated: user.notify = False user.activate()
def handle(self, *args, **options): # Get XML CRM Sources count = options['count'] xml_crm_sources = XMLLinkCRMSource.objects.filter( status=XML_LINK_ENABLED) processed_sources = [] errors = [] # Load XML from source for source in xml_crm_sources: try: self.process_source(source, count) processed_sources.append(source) except Exception as e: errors.append(e) debug_logger.error("Error processing source: %s" % str(source)) debug_logger.error(str(e)) debug_logger.info("Successfully processed %s sources" % len(processed_sources)) if len(errors): debug_logger.error("Encountered %s errors" % len(errors))
def process_source(self, source, count): # load source xml xml = self.xml_from_source(source) # Parse XML data = xmltodict.parse(xml) # Map data mapping = source.mapping raw_shouts = (map_data(data, mapping) or [])[:count] # Collect crm ids source_ids = map(lambda rs: rs.get('id_on_source'), raw_shouts) # Disable current source Shouts with no matching crm ids current_crm_shouts = source.crm_shouts.filter(shout__is_disabled=False) discarded_crm_shouts = current_crm_shouts.filter(~Q( id_on_source__in=source_ids)) discarded_shouts_ids = map(lambda d_crm_s: str(d_crm_s.shout_id), discarded_crm_shouts) Shout.objects.filter(id__in=discarded_shouts_ids).update( is_disabled=True) # Remove them from the index too ShoutIndex()._get_connection().delete_by_query( index=ShoutIndex()._get_index(), body={"query": { "terms": { "_id": discarded_shouts_ids } }}) # Create or update Shouts for raw_shout in raw_shouts: id_on_source = raw_shout.get('id_on_source') try: crm_shout = XMLCRMShout.objects.get(id_on_source=id_on_source) op = 'updated' except XMLCRMShout.DoesNotExist: crm_shout = None op = 'created' finally: shout = crm_shout.shout if crm_shout else None try: if shout: if shout.images: raw_shout['images'] = shout.images shout.is_disabled = False raw_shout['text'] = text_from_html(raw_shout['text']) serializer = ShoutDetailSerializer( instance=shout, data=raw_shout, context={'user': source.user}) serializer.is_valid(raise_exception=True) shout = serializer.save() if not crm_shout: crm_shout = XMLCRMShout.create(attached_object=source, id_on_source=id_on_source, shout=shout, xml_data="test") debug_logger.info("Listing %s was %s successfully" % (id_on_source, op)) except ValidationError as e: debug_logger.error("Listing %s has the following errors %s" % (id_on_source, str(e)))