def get_rsvps(self, event): """ This method is used to get all attendees of an event :param event: Eventbrite event :type event: Event :return: List of RSVPs :rtype: list """ rsvps_url = get_url(self, Urls.RSVPS).format(event.social_network_event_id) response = http_request('GET', url=rsvps_url, headers=self.headers, user_id=self.user.id) all_rsvps = [] data = response.json() page_size = data['pagination']['page_size'] total_records = data['pagination']['object_count'] all_rsvps.extend(data['attendees']) current_page = 1 total_pages = total_records / page_size for page in xrange(1, total_pages): params = {'page': current_page} current_page += 1 # get data for every page response = http_request('GET', rsvps_url, params=params, headers=self.headers, user_id=self.user.id) if response.ok: data = response.json() all_rsvps.extend(data['attendees']) return all_rsvps
def publish_event(self, social_network_event_id): """ This function publishes the Event on Eventbrite. This event is public. :param social_network_event_id: id for event on eventbrite.com :type social_network_event_id: int :exception EventNotPublished: raises this exception when unable to publish event on Eventbrite.com """ # create url to publish event url = get_url(self, Urls.PUBLISH_EVENT).format(str(social_network_event_id)) # params are None. Access token is present in self.headers response = http_request('POST', url, headers=self.headers, user_id=self.user.id) if response.ok: logger.info('| Event has been published |') else: error_message = "Event was not Published. There are some " \ "errors: Details: %s |" % response.text log_error({ 'user_id': self.user.id, 'error': error_message, }) raise EventNotPublished('ApiError: Unable to publish event ' 'on Eventbrite')
def get_member_id(self): """ - If getTalent user has an account on some social network, like Meetup.com, it will have a "member id" for that social network. This "member id" is used to make API subsequent calls to fetch events or RSVPs and relevant data for getTalent user from social network website. :Example: from social_network_service.meetup import Meetup sn = Meetup(user_id=1) sn.get_member_id() - We call this method from connect() of SocialNetworkBase class so that we don't need to get 'member id' of getTalent user while making object of some social network class at different places. (e.g. creating object of Meetup() in when importing events) **See Also** .. seealso:: connect() method defined in SocialNetworkBase class inside social_network_service/base.py. """ logger.info('Getting "member id" of %s(user id:%s) using API of %s.' % (self.user.name, self.user.id, self.social_network.name)) url = get_url(self, SocialNetworkUrls.VALIDATE_TOKEN) # Now we have the URL, access token, and header is set too, response = http_request('POST', url, headers=self.headers, user_id=self.user.id, app=app) if response.ok: return response.json().get('id') else: logger.error('get_member_id: Error:%s.' % response.text)
def _filter_event(self, event): """ This method returns True if given event's group is owned by current user. :param event: event to be tested :type event: dict :return True or False :rtype Boolean """ social_network_group_id = event['group'].get('id') # check if event's group id exists if social_network_group_id: if social_network_group_id in self.social_network_group_ids: return True url = get_url(self, Urls.GROUPS) + '/?sign=true' # Sleep for 10 / 30 seconds to avoid throttling time.sleep(0.34) response = http_request( 'GET', url, params={'group_id': social_network_group_id}, headers=self.headers, user_id=self.user.id) if response.ok: group = response.json() group_organizer = group['results'][0]['organizer'] # group_organizer contains a dict that has member_id and name if str(group_organizer['member_id']) == self.member_id: # save this group id as user's owned groups, so no need to # fetch it again self.social_network_group_ids.append( social_network_group_id) return True return False
def get_rsvps(self, event): """ :param event: event in getTalent database :type event: common.models.event.Event :return: rsvps of given event :rtype: list - We get RSVPs of given event by API of Meetup. - We use this method while importing RSVPs through social network manager. :Example: - Create RSVP class object as sn_rsvp_obj = sn_rsvp_class(social_network=self.social_network, headers=self.headers, user_credentials=user_credentials) - Then call get_all_rsvps() on sn_rsvp_obj by passing events in parameters as follow self.rsvps = sn_rsvp_obj.get_all_rsvps(self.events) - Inside get_all_rsvps(), we call get_rsvps() on class object. - It appends rsvps of an events in a list and returns it **See Also** .. seealso:: get_all_rsvps() method in RSVPBase class inside social_network_service/rsvp/base.py for more insight. :return: list of RSVPs """ rsvps = [] social_network_id = event.social_network_id assert social_network_id is not None rsvps_url = get_url(self, Urls.RSVPS) params = {'event_id': event.social_network_event_id} response = http_request('GET', rsvps_url, params=params, headers=self.headers, user_id=self.user.id) if response.ok: data = response.json() rsvps.extend(data['results']) # next_url determines the pagination, this variable keeps appearing in response if there are more pages # and stops showing when there are no more. We have almost the same code for events' pagination, # might consolidate it. next_url = data['meta']['next'] or None while next_url: # Sleep for 10 / 30 seconds to avoid throttling time.sleep(0.34) # attach the key before sending the request response = http_request('GET', next_url, headers=self.headers, user_id=self.user.id) if response.ok: data = response.json() rsvps.extend(data['results']) next_url = data['meta']['next'] or None if not next_url: break return rsvps
def update_event(self): """ It first creates/ updates a venue on Meetup.com and then passes that venue's id in event's payload to update event location along with event data. :exception EventNotCreated: raises exception if unable to update event on Meetup.com :return: id of event :rtype: int """ # create url to update event url = get_url(self, Urls.EVENT).format(self.social_network_event_id) # create or update venue for event venue_id = self.add_location() # add venue id in event payload to update event venue on Meetup.com self.payload.update({'venue_id': venue_id}) # Sleep for 10 / 30 seconds to avoid throttling time.sleep(0.34) response = http_request('POST', url, params=self.payload, headers=self.headers, user_id=self.user.id) if response.ok: event_id = response.json().get('id') logger.info('| Event %s updated Successfully |' % self.payload['name']) self.data['social_network_event_id'] = event_id return self.save_event() else: error_message = 'Event was not created. Error occurred during ' \ 'event update on Meetup' log_error({'user_id': self.user.id, 'error': error_message}) raise EventNotCreated('ApiError: Unable to update event on Meetup')
def unpublish_event(self, event_id, method=HttpMethods.DELETE): """ This function is used while running unit tests. It deletes the Event from database that were created during the lifetime of a unit test. :param int | long event_id: id of newly created event :param string method: http standard method , default is DELETE :return: True if event is deleted from vendor, False otherwise. :rtype: bool """ # create url to unpublish event url = get_url(self, Urls.EVENT).format(event_id) # Sleep for 10 / 30 seconds to avoid throttling time.sleep(0.34) # params are None. Access token is present in self.headers response = http_request(method, url, headers=self.headers, user_id=self.user.id) if response.ok: logger.info('| Event has been unpublished (deleted) |') else: error_message = "Event was not unpublished (deleted):%s" % response.text log_error({'user_id': self.user.id, 'error': error_message}) raise EventNotUnpublished( 'ApiError: Unable to remove event from %s' % self.social_network.name)
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)
def update_tickets(self, social_network_event_id): """ This method update tickets for specific event on Eventbrite.com. This method should be called after updating event contents on social_network. See "social_network_service.event.Eventbrite.update_event" method for further info :param social_network_event_id: event id which refers to event on eventbrite.com :type social_network_event_id: str :exception TicketsNotCreated (throws exception if unable to update tickets) :return: tickets_id (an id which refers to tickets updated on eventbrite.com) :rtype: str """ tickets_url = get_url(self, Urls.TICKETS).format(social_network_event_id) event = Event.get_by_user_and_social_network_event_id( self.user.id, social_network_event_id) if event.tickets_id: tickets_url = tickets_url + str(event.tickets_id) + '/' else: logger.info('Tickets ID is not available for event with id %s,' ' User: %s' % (social_network_event_id, self.user.name)) raise TicketsNotCreated('ApiError: Unable to update event tickets' ' on Eventbrite as tickets_id was not ' 'found for this event') return self.manage_event_tickets(tickets_url)
def get_groups(self): """ - This function fetches the groups of user from Meetup website for which the user is an organizer. These groups are shown in drop down while creating event on Meetup through Event Creation Form. - This function is called from GET method of class MeetupGroups() inside social_network_service/app/restful/social_network.py :Example: from social_network_service.meetup import Meetup sn = Meetup(user_id=1) sn.get_groups() :return: Meetup groups for which gt-user is an organizer :rtype: list (list of dicts where each dict is likely the response from Meetup API) **See Also** .. seealso:: GET method of class MeetupGroups() inside social_network_service/app/restful/social_network.py """ url = get_url(self, SocialNetworkUrls.GROUPS) params = {'organizer_id': self.user_credentials.member_id} # Sleep for 10 / 30 seconds to avoid throttling time.sleep(0.34) response = http_request('GET', url, params=params, headers=self.headers, user_id=self.user.id) if response.ok: return response.json()['results'] else: return []
def get_events(self): """ We send GET requests to API URL and get data. We also have to handle pagination because Meetup's API does that too. :return: all_events: Events of getTalent user on Meetup.com :rtype all_events: list """ all_events = [] # contains all events of gt-users # page size is 100 so if we have 500 records we will make # 5 requests (using pagination where each response will contain # 100 records). events_url = get_url(self, Urls.EVENTS) # we can specify status=upcoming,past,draft,cancelled etc. By default we # have status=upcoming, so we are not explicitly specifying in fields. meetup_groups = MeetupGroup.filter_by_keywords(user_id=self.user.id) if not meetup_groups: logger.warn( '''No MeetupGroup is associated with this user subscription for Meetup. UserId: %s MemberId: %s ''' % (self.user.id, self.user_credentials.member_id)) return all_events params = { 'group_id': ','.join([str(group.group_id) for group in meetup_groups]), 'status': "upcoming,proposed,suggested", 'fields': 'timezone' } response = http_request('GET', events_url, params=params, headers=self.headers, user_id=self.user.id) if response.ok: data = response.json() all_events = [] all_events.extend(data['results']) # next_url determines the pagination, this variable keeps # appearing in response if there are more pages and stops # showing up when there are no more. next_url = data['meta']['next'] or None while next_url: url = next_url # Sleep for 10 / 30 seconds to avoid throttling time.sleep(0.34) response = http_request('GET', url, headers=self.headers, user_id=self.user.id) if response.ok: data = response.json() all_events.extend(data['results']) next_url = data['meta']['next'] or None if not next_url: break return all_events
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)
def get_events(self, status='live', order_by='start_asc'): """ We send GET requests to Eventbrite API and get already created events by this user on eventbrite.com. We also have to handle pagination because Eventbrite's API does that too. :return all_events: a collection of eventbrite events for specific user :rtype all_events: list """ # create url to fetch events from eventbrite.com search = str(self.member_id) + '/owned_events' events_url = get_url(self, Urls.USER).format(search) params = {'status': status} # initialize event list to empty all_events = [] try: # send a GET request to eventbrite's api to get events for given # user and after start_date response = http_request('GET', events_url, params=params, headers=self.headers, user_id=self.user.id) except: logger.exception('get_events: user_id: %s' % self.user.id) raise if response.ok: # if response is ok, get json data data = response.json() all_events.extend(data['events']) current_page = 1 total_pages = data['pagination']['page_count'] for page in range(1, total_pages): params_copy = params.copy() current_page += 1 params_copy['page'] = current_page try: # get data for every page response = http_request('GET', events_url, params=params_copy, headers=self.headers, user_id=self.user.id) except Exception as e: logger.exception('get_events: user_id: %s' % self.user.id) if response.ok: data = response.json() all_events.extend(data['events']) return all_events
def fetch_event(self, event_id): """ This method creates api url to fetch an event and then sends a GET request to fetch that event. :param str | int | long event_id: social network event id :return: event dict or None """ event_url = get_url(self, SocialNetworkUrls.EVENT).format(event_id) try: response = http_request('get', event_url, headers=self.headers) if response.ok: return response.json() except ResourceNotFound: logger.info('Event not found for url: %s' % event_url) return None
def create_tickets(self, social_network_event_id): """ This method creates tickets for specific event on Eventbrite.com. This method should be called after creating event on social_network. See "social_network_service.event.Eventbrite.create_event" method for further info :param social_network_event_id: event id which refers to event on eventbrite.com :type social_network_event_id: str :exception TicketsNotCreated (throws exception if unable to create tickets) :return: tickets_id (an id which refers to tickets created on eventbrite.com :rtype: str """ tickets_url = get_url(self, Urls.TICKETS).format(social_network_event_id) return self.manage_event_tickets(tickets_url)
def validate_token(self, payload=None): """ :param payload: contains the access token of Facebook (Child class sets the payload) or is None for other social networks. :type payload: dict :return: True if token is valid otherwise False :rtype: bool - This function is called from validate_and_refresh_access_token() social network service base class inside social_network_service/base.py to check the validity of the access token of current user for a specific social network. We take the access token, make request to social network API on url say for Meetup 'https://api.meetup.com/2/member/self' :Example: from social_network_service.meetup import Meetup sn = Meetup(user_id=1) sn.validate_token() **See Also** .. seealso:: __init__() function defined in social network manager inside social_network_service/manager.py. :return status of of access token either True or False. """ status = False url = get_url(self, SocialNetworkUrls.VALIDATE_TOKEN) logger.info("%s access_token validation url: %s", self.social_network.name, url) try: response = requests.get(url, headers=self.headers, params=payload) if response.ok: status = True # If hit rate limit reached for Eventbrite or Meetup, too many requests elif response.status_code == codes.TOO_MANY_REQUESTS: data = response.json() logger.error("HitLimit reached for user(id:%s). Error:%s" % (self.user.id, data)) raise HitLimitReached(data) else: logger.info("Access token has expired for %s(UserId:%s). Social Network is %s." % (self.user.name, self.user.id, self.social_network.name)) except requests.RequestException as error: raise AccessTokenHasExpired('Error: %s, Please connect with %s again from "Profile" page.' % (error.message, self.social_network.name)) return status
def create_event(self): """ This function is used to create Meetup event using vendor's API. It first creates a venue for event. Then venue_id is passed to event_payload. Then a POST request to Meetup API creates event on Meetup.com :exception EventNotCreated: raises exception if unable to publish/create event on Meetup.com. :return: id of event in db :rtype: int """ venue_id = self.add_location() url = get_url(self, Urls.EVENT).format('') self.payload.update({ 'venue_id': venue_id, 'publish_status': 'published' }) logger.info( 'Creating event for %s(user id:%s) using url:%s of API of %s.' % (self.user.name, self.user.id, url, self.social_network.name)) # Sleep for 10 / 30 seconds to avoid throttling time.sleep(0.34) response = http_request('POST', url, params=self.payload, headers=self.headers, user_id=self.user.id) if response.ok: event = response.json() event_id = event['id'] logger.info('| Event %s created Successfully |' % self.payload['name']) self.data['social_network_event_id'] = event_id self.data['url'] = event.get('event_url', '') return self.save_event() else: error_message = 'Event was not Created. Error occurred during draft creation' log_error({'user_id': self.user.id, 'error': error_message}) raise EventNotCreated('ApiError: Unable to create event on Meetup')
def import_meetup_groups(self): """ This method is to fetch user's meetup groups and save them in gt database. """ url = get_url(self, SocialNetworkUrls.GROUPS) params = {'organizer_id': self.user_credentials.member_id} # Sleep for 10 / 30 seconds to avoid throttling time.sleep(0.34) response = http_request('GET', url, params=params, headers=self.headers, user_id=self.user.id) meetup_groups = [] if response.ok: groups = response.json()['results'] for group in groups: meetup_group = MeetupGroup.get_by_group_id(group['id']) if meetup_group: if meetup_group.user_id == self.user.id: meetup_groups.append(meetup_group.to_json()) continue meetup_group = MeetupGroup( group_id=group['id'], user_id=self.user.id, name=group['name'], url_name=group['urlname'], description=group.get('description'), created_datetime=group.get('created'), visibility=group.get('visibility'), country=group.get('country'), state=group.get('state'), city=group.get('city'), timezone=group.get('timezone')) MeetupGroup.save(meetup_group) meetup_groups.append(meetup_group.to_json()) return meetup_groups
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))
def update_event(self): """ This function is used to update an event on Eventbrite.com It uses update_tickets() method to update number of tickets for this event :exception EventNotCreated: throws exception if unable to update event on Eventbrite.com) :return: id of event :rtype: int :Example: In order to updates event first create EventBrite object and it takes user and authentication headers e.g. >> eventbrite = Eventbrite(user=gt_user, headers=authentication_headers) Then call event_gt_to_sn_mapping() method on this object and pass it event dictionary. >> eventbrite.event_gt_to_sn_mapping(event_data) It will create event payload which is required to post event on Eventbrite.com. Now call update_event to update event on Eventbrite.com and in getTalent database. >> eventbrite.update_event() This method returns id of updated getTalent event. """ # create url to update event url = get_url( self, Urls.EVENT).format(str(self.social_network_event_id) + '/') venue_id = self.add_location() # adding venue for the event self.event_payload['event.venue_id'] = venue_id response = http_request('POST', url, params=self.event_payload, headers=self.headers, user_id=self.user.id) if response.ok: # event has been updated on Eventbrite.com event_id = response.json()['id'] # Ticket are going to be created/updated ticket_id = self.update_tickets(event_id) logger.info('| Event %s updated Successfully |' % self.event_payload['event.name.html']) self.data['social_network_event_id'] = event_id self.data['tickets_id'] = ticket_id return self.save_event() else: error_message = 'Event was not updated Successfully' response = response.json() error_detail = response.get('error', '') + ': ' \ + response.get('error_description', '') if error_detail != ': ': error_message += '\n%s' % error_detail log_error({ 'user_id': self.user.id, 'error': error_detail, }) raise EventNotCreated(error_message)
def refresh_access_token(self): """ - When user authorizes Meetup account, we get a refresh token and access token. Access token expires in one hour. Here we refresh the access_token using refresh_token without user involvement and save in user_credentials db table. - This function is called from validate_and_refresh_access_token() defined in SocialNetworkBase class inside social_network_service/base.py :Example: from social_network_service.meetup import Meetup sn = Meetup(user_id=1) sn.refresh_access_token() **See Also** .. seealso:: validate_and_refresh_token() function defined in SocialNetworkBase class inside social_network_service/base.py. :return True if token has been refreshed successfully and False otherwise. :rtype: bool """ status = False user_refresh_token = self.user_credentials.refresh_token auth_url = get_url(self, SocialNetworkUrls.REFRESH_TOKEN, is_auth=True) client_id = self.social_network.client_key client_secret = self.social_network.secret_key payload_data = { 'client_id': client_id, 'client_secret': client_secret, 'grant_type': u'refresh_token', 'refresh_token': user_refresh_token } # Sleep for 10 / 30 seconds to avoid throttling time.sleep(0.34) response = http_request('POST', url=auth_url, data=payload_data, user_id=self.user.id, app=app) if response.ok: try: # access token has been refreshed successfully, need to update # self.access_token and self.headers response = response.json() self.access_token = response.get('access_token') self.headers.update( {'Authorization': 'Bearer ' + self.access_token}) refresh_token = response.get('refresh_token') UserSocialNetworkCredential.query.filter_by(social_network_id=self.social_network.id, member_id=self.user_credentials.member_id).\ update({'access_token': self.access_token, 'refresh_token': refresh_token}) db.session.commit() logger.info("Access token has been refreshed.") status = True except Exception: logger.exception('refresh_access_token: user_id: %s' % self.user.id) else: # Error has been logged inside http_request() pass return status
def add_location(self): """ This function adds the location of event. :exception EventLocationNotCreated: raises exception if unable to create venue on Meetup.com. :exception VenueNotFound: raises exception if unable to find venue in getTalent database. :return id: id of venue created if creation is successful. :rtype id: int :Example: This method is used to create venue or location for event on Meetup. It requires a venue already created in getTalent database otherwise it will raise VenueNotFound exception. Given venue id it first gets venue from database and uses its data to create Meetup object >> meetup = Meetup(user=gt_user, headers=authentication_headers) Then we call add location from create event To get a better understanding see *create_event()* method. """ venue_in_db = Venue.get_by_user_id_social_network_id_venue_id( self.user.id, self.social_network.id, self.venue_id) if not venue_in_db: error_message = 'Venue does not exist in db. Venue id is {}'.format( self.venue_id) log_error({'user_id': self.user.id, 'error': error_message}) raise VenueNotFound( 'Venue not found in database. Kindly specify a valid venue.') if venue_in_db.social_network_venue_id: return venue_in_db.social_network_venue_id url = get_url(self, Urls.VENUES, custom_url=MEETUP_VENUE.format(self.group_url_name)) logger.info( 'Creating venue for %s(user id:%s) using url:%s of API of %s.' % (self.user.name, self.user.id, url, self.social_network.name)) payload = { 'address_1': venue_in_db.address_line_1, 'address_2': venue_in_db.address_line_2, 'city': venue_in_db.city, 'country': venue_in_db.country, 'state': venue_in_db.state, 'name': venue_in_db.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) if response.ok: venue_id = json.loads(response.text)['id'] logger.info('| Venue has been Added |') elif response.status_code == 409: # 409 is returned when our venue is matching existing # venue/venues. So we pick the first one in potential # matches. try: venue_id = json.loads( response.text)['errors'][0]['potential_matches'][0]['id'] logger.info('| Venue was picked from matched records |') except Exception as e: raise EventLocationNotCreated( 'ApiError: Unable to create venue for event', additional_error_info=dict(venue_error=str(e))) else: error_message = 'Venue was not Added. There are some errors.' errors = response.json().get('errors') message = '\nErrors from the social network:\n' message += '\n'.join(error['message'] + ', ' + error['code'] for error in errors) if errors else '' error_message += message log_error({'user_id': self.user.id, 'error': error_message}) raise EventLocationNotCreated( 'ApiError: Unable to create venue for event\n %s' % message) venue_in_db.update(social_network_venue_id=venue_id) return venue_id
def event_sn_to_gt_mapping(self, event): """ We take event's data from social network's API and map its fields to getTalent database fields. Finally we return Event's object to save/update record in getTalent database. We also issue some calls to get updated venue and organizer information. :param event: data from eventbrite API. :type event: dictionary :exception Exception: It raises exception if there is an error getting data from API. :return: event_data, venue_data: event dict object, venue dict data :rtype tuple: event and venue dict data """ venue_obj = None venue_data = None assert event is not None # Get information about event's venue venue_id = event.get('venue_id') if venue_id: venue_obj = Venue.get_by_user_id_and_social_network_venue_id( self.user.id, venue_id) if not venue_obj: try: # Get venues from Eventbrite API for this event. response = http_request('GET', get_url(self, Urls.VENUE).format( event['venue_id']), headers=self.headers, user_id=self.user.id) except: logger.exception('event_sn_to_gt_mapping: user_id: %s,' 'social_network_event_id: %s' % (self.user.id, event['id'])) raise if response.ok: # get json data for venue venue = response.json() venue_data = dict( social_network_id=self.social_network.id, social_network_venue_id=event['venue_id'], user_id=self.user.id, address_line_1=venue['address']['address_1'], address_line_2=venue['address']['address_2'], city=venue['address']['city'], state=venue['address']['region'], zip_code=venue['address']['postal_code'], country=venue['address']['country'], longitude=float(venue['address']['longitude']) if venue and venue.has_key('address') else 0, latitude=float(venue['address']['latitude']) if venue and venue.has_key('address') else 0) # return Event object event_data = dict(social_network_event_id=event['id'], title=event['name']['text'], description=event['description']['html'], social_network_id=self.social_network.id, user_id=self.user.id, social_network_group_id=0, url=event.get('url'), group_url_name='', venue_id=venue_obj.id if venue_obj else None, start_datetime=event['start']['local'], end_datetime=event['end']['local'], registration_instruction='', cost=0, currency=event['currency'], timezone=event['start']['timezone'], max_attendees=event['capacity']) return event_data, venue_data
def create_event(self): """ This function is used to post/create event on Eventbrite.com It uses create_tickets() method to allow user subscriptions and publish_event() to make it public :exception EventNotCreated: throws exception if unable to create event on Eventbrite.com :return: event_id, tickets_id: a tuple containing event_id on Eventbrite and tickets_id for this event :Example: In order to create event first create EventBrite object and it takes user and authentication headers e.g. >> eventbrite = Eventbrite(user=gt_user, headers=authentication_headers) Then call event_gt_to_sn_mapping() method on this object and pass it event dictionary. >> eventbrite.event_gt_to_sn_mapping(event_data) It will create event payload which is required to post event on Eventbrite.com Now call create event to create event on Eventbrite.com >> eventbrite.create_event() This method returns id of getTalent event that was created on Eventbrite.com as well. """ # create url to post/create event on eventbrite.com url = get_url(self, Urls.EVENTS) # adding venue for the event or reuse if already created on # eventbrite.com venue_id = self.add_location() # add venue_id in event payload so it can be associated with this event # on eventbrite self.event_payload['event.venue_id'] = venue_id # create event on eventbrite by sending POST request response = http_request('POST', url, params=self.event_payload, headers=self.headers, user_id=self.user.id) if response.ok: # Event has been created on vendor and saved in draft there. # Now we need to create tickets for it and then publish it. event = response.json() event_id = event['id'] # Ticket are going to be created/updated ticket_id = self.create_tickets(event_id) # Ticket(s) have been created for newly created Event if app.config[TalentConfigKeys.ENV_KEY] not in [ TalentEnvs.JENKINS ]: self.publish_event(event_id) logger.info('| Event %s created Successfully |' % self.event_payload['event.name.html']) self.data['social_network_event_id'] = event_id self.data['tickets_id'] = ticket_id self.data['url'] = event['url'] return self.save_event() else: error_message = 'Event was not created Successfully as draft' response = response.json() error_detail = response.get('error', '') + ': ' \ + response.get('error_description', '') if error_detail != ': ': error_message += '\n%s' % error_detail log_error({ 'user_id': self.user.id, 'error': error_detail, }) raise EventNotCreated(error_message)
def add_location(self): """ This generates a venue object for the event and returns the id of venue. :exception EventLocationNotCreated: throws exception if unable to create or update venue on Eventbrite :exception VenueNotFound: raises exception if venue does not exist in database :return venue_id: id for venue created on eventbrite.com :rtype venue_id: int :Example: This method is used to create venue or location for event on Eventbrite. It requires a venue already created in getTalent database otherwise it will raise VenueNotFound exception. Given venue id it first gets venue from database and uses its data to create Eventbrite object >> eventbrite = Eventbrite(user=gt_user, headers=authentication_headers) Then we call add location from create event To get a better understanding see *create_event()* method. """ # get venue from db which will be created on Eventbrite venue = Venue.get_by_user_id_social_network_id_venue_id( self.user.id, self.social_network.id, self.venue_id) if venue: if venue.social_network_venue_id: # there is already a venue on Eventbrite with this info. return venue.social_network_venue_id # This dict is used to create venue payload = { 'venue.name': venue.address_line_1, 'venue.address.address_1': venue.address_line_1, 'venue.address.address_2': venue.address_line_2, 'venue.address.region': venue.state, 'venue.address.city': venue.city, # 'venue.address.country': venue.country, 'venue.address.postal_code': venue.zip_code, 'venue.address.latitude': venue.latitude, 'venue.address.longitude': venue.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) if response.ok: logger.info('| Venue has been created |') venue_id = response.json().get('id') venue.update(social_network_venue_id=venue_id) return venue_id else: error_message = "Venue was not Created. There are some " \ "errors: Details: %s " % response message = '\nErrors from the Social Network:\n' message += \ ''.join(response.json().get('error') + ',' + response.json().get('error_description')) error_message += message log_error({'error': error_message, 'user_id': self.user.id}) raise EventLocationNotCreated( 'ApiError: Unable to create venue for event\n %s' % message) else: error_message = 'Venue with ID = %s does not exist in db.' \ % self.venue_id log_error({ 'user_id': self.user.id, 'error': error_message, }) raise VenueNotFound('Venue not found in database. Kindly create' ' venue first.')
def get_attendee_for_rsvp_via_webhook(self, rsvp): """ :param rsvp: rsvp is likely the response of social network API. :type rsvp: dict :return: attendee :rtype: object Webhook returns data for RSVP as: { u'config': { u'action': u'order.placed', u'user_id': u'149011448333', u'endpoint_url': u'https://emails.ngrok.io/webhook/1', u'webhook_id': u'274022' }, u'api_url': u'https://www.eventbriteapi.com/v3/orders/573384540/' } we extract order_id from above response and treat it as social_network_rsvp_id. So, rsvp object in this method looks like { 'rsvp_id': 573384540 } When we request Eventbrite API with above rsvp_id, we get response as { u'status': u'placed', u'first_name': u'Muhammad', u'last_name': u'Aslam', u'name': u'Muhammad Aslam', u'created': u'2016-11-29T15:52:15Z', u'event_id': u'29641929810', u'changed': u'2016-11-29T15:52:16Z', u'email': u'*****@*****.**', u'costs': { u'payment_fee': {u'currency': u'USD', u'display': u'$0.00', u'value': 0, u'major_value': u'0.00' }, u'gross': { u'currency': u'USD', u'display': u'$0.00', u'value': 0, u'major_value': u'0.00'}, u'eventbrite_fee': {u'currency': u'USD', u'display': u'$0.00', u'value': 0, u'major_value': u'0.00'}, u'tax': {u'currency': u'USD', u'display': u'$0.00', u'value': 0, u'major_value': u'0.00'}, u'base_price': {u'currency': u'USD', u'display': u'$0.00', u'value': 0, u'major_value': u'0.00'} }, u'time_remaining': None, u'id': u'575508020', u'resource_uri': u'https://www.eventbriteapi.com/v3/orders/575508020/' } - This function is used to get the data of candidate related to given rsvp. It attaches all the information in attendee object. `attendees` is a utility object we share in calls that contains pertinent data. - This method is called from get_attendee() defined in this file. :Example: attendee = self.get_attendee_for_rsvp_via_webhook(rsvp) **See Also** .. seealso:: get_attendee() method in this class. """ order_url = get_url(self, Urls.ORDER).format(rsvp['rsvp_id']) order_response = http_request('GET', order_url, headers=self.headers, user_id=self.user.id) if order_response.ok: data = order_response.json() # get event_id social_network_event_id = data['event_id'] event = Event.get_by_user_id_social_network_id_vendor_event_id( self.user.id, self.social_network.id, social_network_event_id) if not event: raise EventNotFound( 'Event is not present in db, social_network_event_id is %s. User Id: %s' % (social_network_event_id, self.user.id)) created_datetime = datetime.strptime(data['created'][:19], "%Y-%m-%dT%H:%M:%S") attendee = Attendee() attendee.event = event attendee.first_name = data['first_name'] attendee.full_name = data['name'] attendee.last_name = data['last_name'] attendee.added_time = created_datetime attendee.rsvp_status = 'yes' if data[ 'status'] == 'placed' else data['status'] attendee.email = data['email'] attendee.vendor_rsvp_id = rsvp['rsvp_id'] attendee.gt_user_id = self.user.id attendee.social_network_id = self.social_network.id # TODO: This won't work now, need to figure out a way attendee.vendor_img_link = \ "<img class='pull-right'" \ " style='width:60px;height:30px' " \ "src='/web/static/images/activities/eventbrite_logo.png'/>" # GET attendees of event rsvps_url = get_url(self, Urls.RSVPS).format( event.social_network_event_id) response_attendees = http_request('GET', rsvps_url, headers=self.headers) event_attendees = response_attendees.json()['attendees'] for event_attendee in event_attendees: # Get profile url of candidate to save if event_attendee['created'] == order_response.json( )['created']: # In case of Eventbrite, we have a Attendee object created # on Eventbrite website. We save that link as profile url. attendee.social_profile_url = event_attendee[ 'resource_uri'] break return attendee