Ejemplo n.º 1
0
 def __init__(self, *args, **kwargs):
     super(Twitter, self).__init__(exclude_fields=("api_url", ), **kwargs)
     self.consumer_key = self.social_network.client_key
     if not self.consumer_key:
         raise InternalServerError('Twitter client_key not set correctly')
     self.consumer_secret = self.social_network.secret_key
     if not self.consumer_secret:
         raise InternalServerError('Twitter secret key not set correctly')
     self.auth = tweepy.OAuthHandler(
         self.consumer_key, self.consumer_secret,
         SocialNetworkApiUrl.TWITTER_CALLBACK % self.user.id)
Ejemplo n.º 2
0
    def add_venue_to_sn(self, venue_data):
        """
        This function sends a POST request to Meetup api to create a venue for event.
        :param dict venue_data: a dictionary containing data required to create a venue
        """
        if not venue_data.get('group_url_name'):
            raise InvalidUsage("Mandatory Input Missing: group_url_name",
                               error_code=custom_codes.MISSING_REQUIRED_FIELDS)
        url = get_url(self, SocialNetworkUrls.VENUES,
                      custom_url=MEETUP_VENUE).format(
                          venue_data['group_url_name'])
        payload = {
            'address_1': venue_data['address_line_1'],
            'address_2': venue_data.get('address_line_2'),
            'city': venue_data['city'],
            'country': venue_data['country'],
            'state': venue_data['state'],
            'name': venue_data['address_line_1']
        }
        # Sleep for 10 / 30 seconds to avoid throttling
        time.sleep(0.34)
        response = http_request('POST',
                                url,
                                params=payload,
                                headers=self.headers,
                                user_id=self.user.id)
        json_resp = response.json()
        if response.ok:
            venue_id = json_resp['id']
            logger.info('Venue has been Added. Venue Id: %s', venue_id)
        elif response.status_code == codes.CONFLICT:
            # 409 is returned when our venue is matching existing
            # venue/venues.
            try:
                match_id = json_resp['errors'][0]['potential_matches'][0]['id']
            except:
                raise InternalServerError('Invalid response from Meetup',
                                          error_code=INVALID_MEETUP_RESPONSE)
            venue = Venue.get_by_user_id_and_social_network_venue_id(
                self.user.id, match_id)
            if venue:
                raise InvalidUsage(
                    'Venue already exists in getTalent database',
                    additional_error_info=dict(id=venue.id),
                    error_code=VENUE_EXISTS_IN_GT_DATABASE)
            venue_id = json_resp['errors'][0]['potential_matches'][0]['id']
        else:
            raise InternalServerError(
                'ApiError: Unable to create venue for Meetup',
                additional_error_info=dict(venue_error=json_resp))

        venue_data['user_id'] = self.user.id
        venue_data['social_network_venue_id'] = venue_id
        return SocialNetworkBase.save_venue(venue_data)
Ejemplo n.º 3
0
def get_url(class_object, key, custom_url=None, is_auth=None):
    """
    This returns the required URL to make HTTP request on some social-network website
    :param EventBase|SocialNetworkBase class_object: SocialNetwork class object
    :param string key: Requested Key
    :param custom_url: Custom API URL different from class_object.api_url
    :param bool is_auth: if is_auth is true then use vendor auth url, otherwise use api url
    :rtype: string
    """
    social_network_name = class_object.social_network.name
    social_network_urls = getattr(SocialNetworkUrls, social_network_name.upper())
    if app.config[TalentConfigKeys.ENV_KEY] in [TalentEnvs.DEV, TalentEnvs.JENKINS] \
            and social_network_name.lower() in MOCK_VENDORS:
        # There are currently two types of URLs. i.e Auth and API url.
        auth_part = AUTH if is_auth else API
        api_url = MockServiceApiUrl.MOCK_SERVICE % (auth_part, social_network_name.lower())
    else:
        api_url = (class_object.auth_url if is_auth else class_object.api_url) if not custom_url else custom_url

    try:
        relative_url = social_network_urls[key.lower()]
    except KeyError as error:
        logger.error(error.message)
        raise InternalServerError('Error occurred while getting URL for %s. (SocialNetwork:%s)'
                                  % (key, social_network_name))

    return relative_url.format(api_url, '{}')
Ejemplo n.º 4
0
    def authenticate(self):
        """
        Here we use OAuthHandler of tweepy to give us request token. We use that request token and
        redirect the user to Twitter website where user can add its credentials.
        Once user is successfully logged-in, user is again redirected to URL as specified by callback URL of
        OAuthHandler which is http://127.0.0.1:8007/v1/twitter-callback/<int:user_id> (for local environment)
        in this case.
        In case of failure, we log the error and raises InternalServerError.

        This method is called from endpoint http://127.0.0.1:8007/v1/twitter-auth.
        """
        try:

            # redirect_url takes the user to login-page of Twitter to authorize getTalent app.
            redirect_url = self.auth.get_authorization_url()
            # Once user is successfully logged-in to Twitter account, it is redirected to callback URL where
            # we need to exchange request token with access token. This access token is used to access Twitter API.
            # So, we save request_token in the redis and retrieve this in callback() method.
            redis_store.set('twitter_request_token_%s' % self.user.id,
                            json.dumps(self.auth.request_token))
            # redirect the user to Twitter website for authorization.
            return redirect_url
        except tweepy.TweepError as error:
            logger.exception(
                'Error! Failed to get request token from Twitter for User(id:%s).\nError:%s'
                % (self.user.id, error.message))
            raise InternalServerError("Couldn't connect to Twitter account.")
Ejemplo n.º 5
0
 def application_based_auth(self):
     """
     This function does application based authentication with Twitter. This do not need any user interaction
     to connect with Twitter account because it makes request on behalf of App.
     It raises InternalServerError in case authentication fails.
     Here are the detailed docs https://dev.twitter.com/oauth/application-only.
     :return: Access token for getTalent app to access Twitter's API.
     :rtype: str
     """
     combined_key = self.consumer_key + ':' + self.consumer_secret
     combined_key = base64.b64encode(combined_key)
     headers = {
         'Authorization': 'Basic %s' % combined_key,
         'Content-Type': 'application/x-www-form-urlencoded'
     }
     data = {'grant_type': 'client_credentials'}
     result = http_request('post',
                           APPLICATION_BASED_AUTH_URL,
                           headers=headers,
                           data=data,
                           app=app)
     if result.ok:
         logger.info(
             'Successfully authenticated from Twitter API. User(id:%s).',
             self.user.id)
         access_token = result.json()['access_token']
         return access_token
     raise InternalServerError(
         'Error Occurred while authenticating from Twitter')
Ejemplo n.º 6
0
    def add_venue_to_sn(self, venue_data):
        """
        This function sends a POST request to Eventbrite api to create a venue for event.
        :param dict venue_data: a dictionary containing data required to create a venue
        """

        payload = {
            'venue.name': venue_data['address_line_1'],
            'venue.address.address_1': venue_data['address_line_1'],
            'venue.address.address_2': venue_data.get('address_line_2'),
            'venue.address.region': venue_data['state'],
            'venue.address.city': venue_data['city'],
            'venue.address.postal_code': venue_data.get('zip_code'),
            'venue.address.latitude': venue_data.get('latitude'),
            'venue.address.longitude': venue_data.get('longitude')
        }
        # create url to send post request to create venue
        url = get_url(self, Urls.VENUES)
        response = http_request('POST',
                                url,
                                params=payload,
                                headers=self.headers,
                                user_id=self.user.id)
        json_resp = response.json()
        if response.ok:
            logger.info('|  Venue has been created  |')
            venue_id = json_resp.get('id')
        else:
            raise InternalServerError(
                'ApiError: Unable to create venue for Eventbrite',
                additional_error_info=dict(venue_error=json_resp))

        venue_data['user_id'] = self.user.id
        venue_data['social_network_venue_id'] = venue_id
        return SocialNetworkBase.save_venue(venue_data)
Ejemplo n.º 7
0
def callback(user_id):
    """
    Once user is successfully logged-in to Twitter account, it is redirected to this endpoint to get access token,
    Here we create object of Twitter class defined in social_network/twitter.py and call its method callback().
    In request object, we get a parameter "oauth_verifier" which we use to get access token for the user.
    **See Also**
        .. seealso:: callback() method defined in Twitter class inside social_network/twitter.py.
    """
    if 'oauth_verifier' in request.args:
        twitter_obj = Twitter(user_id=user_id, validate_credentials=False)
        return twitter_obj.callback(request.args['oauth_verifier'])
    raise InternalServerError(
        'You did not provide valid credentials. Unable to connect! Please try again.'
    )
Ejemplo n.º 8
0
    def save_attendee_source(self, attendee):
        """
        :param attendee: attendees is a utility object we share in calls that
                 contains pertinent data.
        :type attendee: object of class Attendee defined in utilities.py

        - This method checks if the event is present in candidate_source db
         table. If does not exist, it adds record, otherwise updates the
         record. It then appends id of source in attendee object to be saved in
         candidate table.

        - This method is called from process_rsvps() defined in
          RSVPBase class inside social_network_service/rsvp/base.py.

        - We use this method while importing RSVPs through social network

        :Example:

            attendee = self.save_attendee_source(attendee)

        **See Also**
            .. seealso:: process_rsvps() method in EventBase class
        :return attendee:
        :rtype: Attendee
        """
        attendee.event.description = attendee.event.description[:1000].encode('utf-8') if attendee.event.description \
            else 'Not given'
        candidate_source = {
            "source": {
                "description": attendee.event.description,
                "notes": attendee.event.title
            }
        }
        access_token = User.generate_jw_token(user_id=self.user.id)
        header = {
            'Content-Type': 'application/json',
            'Authorization': access_token
        }
        response = http_request('POST', UserServiceApiUrl.DOMAIN_SOURCES, headers=header,
                                data=json.dumps(candidate_source))
        # Source already exists
        if response.status_code == requests.codes.bad:
            attendee.candidate_source_id = response.json()['error']['source_id']
        elif response.status_code != requests.codes.created:
            logger.exception(response.text)
            raise InternalServerError(error_message="Error while creating candidate source")
        else:
            attendee.candidate_source_id = response.json()['source']['id']

        return attendee
Ejemplo n.º 9
0
    def get(self, **kwargs):
        """
        This action returns a list of user timezones.

            :Example:

                    headers = {
                                'Authorization': 'Bearer <access_token>'
                               }
                    response = requests.get(
                                                API_URL + '/data/timezones',
                                                headers=headers,
                                            )




        .. Response:
                {
                  "timezones": [
                    {
                      "name": "GMT +00:00  Africa/Abidjan",
                      "value": "Africa/Abidjan"
                    },
                    {
                      "name": "GMT +00:00  Africa/Accra",
                      "value": "Africa/Accra"
                    },
                    {
                      "name": "GMT +00:00  Africa/Bamako",
                      "value": "Africa/Bamako"
                    },
                    {
                      "name": "GMT +00:00  Africa/Banjul",
                      "value": "Africa/Banjul"
                    },
                    .
                    .
                    .
                    .
                    .
                   ]
                }
        """
        try:
            timezones = get_timezones()
        except Exception:
            raise InternalServerError('APIError: Unable to get timezones.')
        return dict(timezones=timezones)
Ejemplo n.º 10
0
 def resolve_meetup_groups(self, args, request, info):
     """
     Resolves current user's Meetup groups.
     """
     user_id = request.user.id
     try:
         meetup = Meetup(user_id=user_id)
         groups = meetup.get_groups()
     except Exception as e:
         raise InternalServerError(e.message)
     keys = ('id', 'name', 'urlname')
     return [
         MeetupGroupType(
             **{k: v
                for k, v in group.iteritems() if k in keys})
         for group in groups
     ]
Ejemplo n.º 11
0
 def create_webhook(cls, user_credentials):
     """
     :param user_credentials: User's social network credentials for which
             we need to create webhook. Webhook is created to be updated
             about any RSVP on an
             event of Eventbrite.
     :type user_credentials:  common.models.user.UserSocialNetworkCredential
     - This method creates a webhook to stream the live feed of RSVPs of
         Eventbrite events to the getTalent app. Once we have the webhook
         id for given user, we update user credentials in db.
     - It also performs a check which ensures that webhook is not generated
         every time code passes through this flow once a webhook has been
         created for a user (since webhook don't expire and are unique for
         every user).
     - This method is called from save_user_credentials_in_db() defined in
         Eventbrite class inside social_network_service/eventbrite.py.
     **See Also**
     .. seealso:: save_user_credentials_in_db() function defined in Eventbrite
         class inside social_network_service/eventbrite.py.
     .. seealso:: get_access_and_refresh_token() function defined in Eventbrite
         class inside social_network_service/eventbrite.py.
     """
     url = user_credentials.social_network.api_url + "/webhooks/"
     payload = {
         'endpoint_url':
         SocialNetworkApiUrl.WEBHOOK % user_credentials.user_id,
         'actions':
         ','.join([
             ACTIONS['published'], ACTIONS['unpublished'], ACTIONS['rsvp']
         ])
     }
     headers = {'Authorization': 'Bearer ' + user_credentials.access_token}
     response = http_request('POST',
                             url,
                             params=payload,
                             headers=headers,
                             user_id=user_credentials.user.id)
     try:
         webhook_id = response.json()['id']
         user_credentials.update(webhook=webhook_id)
     except Exception:
         logger.exception('create_webhook: user_id: %s' %
                          user_credentials.user.id)
         raise InternalServerError(
             "Eventbrite Webhook wasn't created successfully")
Ejemplo n.º 12
0
    def callback(self, oauth_verifier):
        """
        This method is called from endpoint http://127.0.0.1:8007/v1/twitter-callback/<int:user_id>
        defined in app.py.
        Here we use "oauth_verifier" to get access token for the user.
        If we get any error in getting access token, we log the error and raise InternalServerError.

        Once we have the access_token, we get the member_id (id of getTalent user on Twitter's website) of user
        from Twitter API and save its credentials in database table "UserSocialNetworkCredential".

        :param string oauth_verifier: Token received from Twitter when user successfully connected to its account.
        """
        self.auth.request_token = json.loads(
            redis_store.get('twitter_request_token_%s' % self.user.id))
        redis_store.delete('twitter_request_token_%s' % self.user.id)
        try:
            self.auth.get_access_token(oauth_verifier)
        except tweepy.TweepError as error:
            logger.exception(
                'Failed to get access token from Twitter for User(id:%s). \nError: %s'
                % (self.user.id, error.message))
            raise InternalServerError(
                'Failed to get access token from Twitter')

        access_token = self.auth.access_token
        # This may be used later
        # access_token_secret = self.auth.access_token_secret
        api = tweepy.API(self.auth)
        twitter_user = api.me()
        user_credentials = UserSocialNetworkCredential.get_by_user_and_social_network_id(
            self.user.id, self.social_network.id)
        if not user_credentials:
            user_credentials_obj = UserSocialNetworkCredential(
                user_id=self.user.id,
                social_network_id=self.social_network.id,
                member_id=twitter_user.id,
                access_token=access_token)
            UserSocialNetworkCredential.save(user_credentials_obj)

        logger.info(
            'User(id:%s) is now connected with Twitter. Member id on twitter is %s'
            % (self.user.id, twitter_user.id))
        return redirect(get_web_app_url())
Ejemplo n.º 13
0
    def connect(self, code):
        """
        This connects user with social-network's account. e.g. on Meetup or Eventbrite etc.
        This gets access token and refresh tokens for user and it also updates these tokens for previously connected
        users. It also gets member_id of getTalent user for requested social-network website.
        :param string code: code to exchange for access token and refresh token.
        """
        access_token, refresh_token = self.get_access_and_refresh_token(self.user.id, self.social_network,
                                                                        code_to_get_access_token=code)
        self.headers = {'Authorization': 'Bearer ' + access_token}
        # GET member_id of getTalent user
        member_id = self.get_member_id()
        if not member_id:
            raise InternalServerError('Could not get member id from social-network:%s' % self.social_network.name)
        # Check all user_social_network_credentials in database against this member_id
        records_in_db = UserSocialNetworkCredential.filter_by_keywords(social_network_id=self.social_network.id,
                                                                       member_id=member_id)
        user_credentials_dict = dict(user_id=self.user.id, social_network_id=self.social_network.id,
                                     access_token=access_token, refresh_token=refresh_token, member_id=member_id)

        if not records_in_db:  # No record found in database
            return self.save_user_credentials_in_db(user_credentials_dict)

        if len(records_in_db) >= 1:
            for record in records_in_db:
                if record.user.id == self.user.id:
                    error_message = 'You are already connected to this account.'
                    logger.error(error_message)
                    raise InvalidUsage(error_message)
                elif record.user.domain_id == self.user.domain_id:
                    error_message = 'Some other user is already in your domain with this account. user_id:%s, ' \
                                    'social_network:%s , member_id:%s.' % (self.user.id,
                                                                           self.social_network.name.title(), member_id)
                    logger.error(error_message)
                    raise InvalidUsage(error_message)
                else:
                    # updating new  access and refresh tokens for all user connected with same meetup account.
                    record.access_token = access_token
                    record.refresh_token = refresh_token

            db.session.commit()
            return self.save_user_credentials_in_db(user_credentials_dict)
Ejemplo n.º 14
0
    def create_event_organizer(self, data):
        """
        This method sends a POST request to Eventbrite API to create an event organizer.
        :param dict[str, T] data: organizer data
        :return: organizer id on Eventbrite
        :rtype string
        """
        mandatory_input_data = ['name', 'about']
        # gets fields which are missing
        missing_items = find_missing_items(data, mandatory_input_data)
        if missing_items:
            raise InvalidUsage("Mandatory Input Missing: %s" % missing_items)

        payload = {
            'organizer.name': data['name'],
            'organizer.description.html': data['about']
        }
        # create url to send post request to create organizer
        url = get_url(self, Urls.ORGANIZERS)
        response = http_request('POST',
                                url,
                                params=payload,
                                headers=self.headers,
                                user_id=self.user.id)
        json_response = response.json()
        if response.ok:
            return json_response['id']
        elif response.status_code == requests.codes.BAD_REQUEST and json_response.get(
                'error') == "ARGUMENTS_ERROR":
            raise InvalidUsage(
                'Organizer name `{}` already exists on Eventbrite'.format(
                    data['name']),
                error_code=ORGANIZER_ALREADY_EXISTS)
        raise InternalServerError(
            'Error occurred while creating organizer.',
            additional_error_info=dict(error=json_response))
Ejemplo n.º 15
0
    def save_attendee_as_candidate(self, attendee):
        """
        :param attendee: attendees is a utility object we share in calls that
         contains pertinent data.
        :type attendee: object of class Attendee defined in utilities.py

        - This method adds the attendee as a new candidate if it is not present
         in the database already, otherwise it updates the previous record. It
         then appends the candidate_id to the attendee object and add/updates record in
         candidate_social_network db table. It then returns attendee object.

        - This method is called from process_rsvps() defined in
          RSVPBase class inside social_network_service/rsvp/base.py.

        - We use this method while importing RSVPs through social network
        :Example:

            attendee = self.save_attendee_as_candidate(attendee)

        **See Also**
            .. seealso:: process_rsvps() method in EventBase class
        :return attendee:
        :rtype: Attendee
        """
        candidate_in_db = None
        request_method = 'post'
        domain_id = User.get_domain_id(attendee.gt_user_id)
        candidate_by_email = CandidateEmail.get_email_in_users_domain(domain_id, attendee.email)
        if candidate_by_email:
            candidate_in_db = candidate_by_email.candidate
        if not candidate_in_db:
            # TODO: Need to handle multiple sources per candidate
            candidate_in_db = Candidate.filter_by_keywords(first_name=attendee.first_name,
                                                           last_name=attendee.last_name,
                                                           source_id=attendee.candidate_source_id,
                                                           source_product_id=attendee.source_product_id)

            if candidate_in_db:
                candidate_in_db = candidate_in_db[0]
                # Check if candidate's domain is same as user's domain
                if not candidate_in_db.user.domain_id == domain_id:
                    candidate_in_db = None

        # To create candidates, user must have be associated with talent_pool
        talent_pools = TalentPool.filter_by_keywords(user_id=attendee.gt_user_id)
        talent_pool_ids = map(lambda talent_pool: talent_pool.id, talent_pools)

        if not talent_pool_ids:
            raise InternalServerError("save_attendee_as_candidate: user doesn't have any talent_pool")

        # Create data dictionary
        data = {'first_name': attendee.first_name,
                'last_name': attendee.last_name,
                'source_id': attendee.candidate_source_id,
                'source_product_id': attendee.source_product_id,
                'talent_pool_ids': dict(add=talent_pool_ids)
                }
        social_network_data = {
            'name': attendee.event.social_network.name,
            'profile_url': attendee.social_profile_url
        }

        # Update if already exist
        if candidate_in_db:
            candidate_id = candidate_in_db.id
            data.update({'id': candidate_id})
            request_method = 'patch'
            # Get candidate's social network if already exist
            candidate_social_network_in_db = \
                CandidateSocialNetwork.get_by_candidate_id_and_sn_id(candidate_id, attendee.social_network_id)
            if candidate_social_network_in_db:
                social_network_data.update({'id': candidate_social_network_in_db.id})

        if attendee.email:
            data.update({'emails': [{'address': attendee.email,
                                     'label': EmailLabel.PRIMARY_DESCRIPTION,
                                     'is_default': True
                                     }]
                         })
        # Update social network data to be sent with candidate
        data.update({'social_networks': [social_network_data]})
        access_token = User.generate_jw_token(user_id=self.user.id)
        header = {
            'Content-Type': 'application/json',
            'Authorization': access_token
        }
        resp = http_request(request_method, url=CandidateApiUrl.CANDIDATES, headers=header,
                            data=json.dumps(dict(candidates=[data])), app=app)
        data_resp = resp.json()
        if resp.status_code not in [codes.CREATED, codes.OK]:
            error_message = 'save_attendee_as_candidate: candidate creation failed. Error:%s' % data_resp
            logger.error(error_message)
            raise InternalServerError(error_message)
        attendee.candidate_id = data_resp['candidates'][0]['id']
        return attendee