def update_user_email(self, new_email, old_email): """ Adds/updates Sailthru when a user email address is changed Args: username(str): A string representation of user identifier old_email(str): Original email address Returns: None """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return # ignore if email not changed if new_email == old_email: return sailthru_parms = {"id": old_email, "key": "email", "keysconflict": "merge", "keys": {"email": new_email}} try: sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) sailthru_response = sailthru_client.api_post("user", sailthru_parms) except SailthruClientError as exc: log.error("Exception attempting to update email for %s in Sailthru - %s", old_email, unicode(exc)) raise self.retry(exc=exc, countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) if not sailthru_response.is_ok(): error = sailthru_response.get_error() log.error("Error attempting to update user email address in Sailthru: %s", error.get_message()) if _retryable_sailthru_error(error): raise self.retry(countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries)
def update_user(self, sailthru_vars, email, site=None, new_user=False, activation=False): """ Adds/updates Sailthru profile information for a user. Args: sailthru_vars(dict): User profile information to pass as 'vars' to Sailthru email(str): User email address new_user(boolean): True if new registration activation(boolean): True if activation request Returns: None """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) try: sailthru_response = sailthru_client.api_post("user", _create_email_user_param(sailthru_vars, sailthru_client, email, new_user, email_config, site=site)) except SailthruClientError as exc: log.error("Exception attempting to add/update user %s in Sailthru - %s", email, unicode(exc)) raise self.retry(exc=exc, countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) if not sailthru_response.is_ok(): error = sailthru_response.get_error() log.error("Error attempting to add/update user in Sailthru: %s", error.get_message()) if _retryable_sailthru_error(error): raise self.retry(countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) return # if activating user, send welcome email if activation and email_config.sailthru_activation_template: scheduled_datetime = datetime.utcnow() + timedelta(seconds=email_config.welcome_email_send_delay) try: sailthru_response = sailthru_client.api_post( "send", { "email": email, "template": email_config.sailthru_activation_template, "schedule_time": scheduled_datetime.strftime('%Y-%m-%dT%H:%M:%SZ') } ) except SailthruClientError as exc: log.error("Exception attempting to send welcome email to user %s in Sailthru - %s", email, unicode(exc)) raise self.retry(exc=exc, countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) if not sailthru_response.is_ok(): error = sailthru_response.get_error() log.error("Error attempting to send welcome email to user in Sailthru: %s", error.get_message()) if _retryable_sailthru_error(error): raise self.retry(countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries)
def add_email_marketing_cookies(sender, response=None, user=None, **kwargs): # pylint: disable=unused-argument """ Signal function for adding any cookies needed for email marketing Args: response: http response object user: The user object for the user being changed Returns: response: http response object with cookie added """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return response post_parms = { 'id': user.email, 'fields': {'keys': 1}, 'vars': {'last_login_date': datetime.datetime.now().strftime("%Y-%m-%d")} } # get anonymous_interest cookie to capture usage before logon request = crum.get_current_request() if request: sailthru_content = request.COOKIES.get('anonymous_interest') if sailthru_content: post_parms['cookies'] = {'anonymous_interest': sailthru_content} try: sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) log.info( 'Sending to Sailthru the user interest cookie [%s] for user [%s]', post_parms.get('cookies', ''), user.email ) sailthru_response = \ sailthru_client.api_post("user", post_parms) except SailthruClientError as exc: log.error("Exception attempting to obtain cookie from Sailthru: %s", unicode(exc)) return response if sailthru_response.is_ok(): if 'keys' in sailthru_response.json and 'cookie' in sailthru_response.json['keys']: cookie = sailthru_response.json['keys']['cookie'] response.set_cookie( 'sailthru_hid', cookie, max_age=365 * 24 * 60 * 60, # set for 1 year domain=settings.SESSION_COOKIE_DOMAIN, path='/', ) else: log.error("No cookie returned attempting to obtain cookie from Sailthru for %s", user.email) else: error = sailthru_response.get_error() # generally invalid email address log.info("Error attempting to obtain cookie from Sailthru: %s", error.get_message()) return response
def handle_noargs(self, **kwargs): api = SailthruClient(settings.SAILTHRU_API_KEY, settings.SAILTHRU_API_SECRET) pp = pprint.PrettyPrinter(indent=4) i = 0 total_i = 0 out_file_count = 0 out_file = None with open('/home/ubuntu/Project/ecomarket/all-users.csv', 'rb') as csvfile: reader = csv.reader(csvfile) headers = None for row in reader: if headers is None: headers = row continue row = dict(zip(headers, row)) non_empty_row = {} for k, v in row.items(): if v is not None: v = v.strip() if len(v) == 0: v = None non_empty_row[k] = v st_user = api.api_get('user', {'id': non_empty_row['Profile Id']}) if st_user is None: print "Cannot find user '%s'" % ( non_empty_row['Profile Id'], ) body = st_user.get_body() st_user_vars = body['vars'] if st_user_vars is None: continue for key in st_user_vars.keys(): try: if st_user_vars[k] is not None: if type(st_user_vars[k]) == str: st_user_vars[k] = st_user_vars[k].strip() if st_user_vars[k] == '': st_user_vars[k] = None except: pass new_vars = clean_user(st_user_vars) email = body['keys']['email'] if out_file is None or i > 5000: i = 0 if out_file is not None: out_file.close() out_file_count += 1 out_file = open('batch_%d.txt' % (out_file_count, ), 'wb') out_file.write( json.dumps({ 'email': email, 'vars': new_vars }, default=_encoder_default) + "\n") i += 1 total_i += 1 print "%d %d %d" % (i, total_i, out_file_count)
def update_user(self, username, new_user=False, activation=False): """ Adds/updates Sailthru profile information for a user. Args: username(str): A string representation of user identifier Returns: None """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return # get user user = User.objects.select_related('profile').get(username=username) if not user: log.error("User not found during Sailthru update %s", username) return # get profile profile = user.profile if not profile: log.error("User profile not found during Sailthru update %s", username) return sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) try: sailthru_response = sailthru_client.api_post("user", _create_sailthru_user_parm(user, profile, new_user, email_config)) except SailthruClientError as exc: log.error("Exception attempting to add/update user %s in Sailthru - %s", username, unicode(exc)) raise self.retry(exc=exc, countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) if not sailthru_response.is_ok(): error = sailthru_response.get_error() # put out error and schedule retry log.error("Error attempting to add/update user in Sailthru: %s", error.get_message()) raise self.retry(countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) # if activating user, send welcome email if activation and email_config.sailthru_activation_template: try: sailthru_response = sailthru_client.api_post("send", {"email": user.email, "template": email_config.sailthru_activation_template}) except SailthruClientError as exc: log.error("Exception attempting to send welcome email to user %s in Sailthru - %s", username, unicode(exc)) raise self.retry(exc=exc, countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) if not sailthru_response.is_ok(): error = sailthru_response.get_error() # probably an invalid template name, just put out error log.error("Error attempting to send welcome email to user in Sailthru: %s", error.get_message())
def force_unsubscribe_all(sender, **kwargs): # pylint: disable=unused-argument """ Synchronously(!) unsubscribes the given user from all Sailthru email lists. In the future this could be moved to a Celery task, however this is currently only used as part of user retirement, where we need a very reliable indication of success or failure. Args: email: Email address to unsubscribe new_email (optional): Email address to change 3rd party services to for this user (used in retirement to clear personal information from the service) Returns: None """ email = kwargs.get('email', None) new_email = kwargs.get('new_email', None) if not email: raise TypeError( 'Expected an email address to unsubscribe, but received None.') email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return sailthru_parms = { "id": email, "optout_email": "all", "fields": { "optout_email": 1 } } # If we have a new email address to change to, do that as well if new_email: sailthru_parms["keys"] = {"email": new_email} sailthru_parms["fields"]["keys"] = 1 sailthru_parms["keysconflict"] = "merge" try: sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) sailthru_response = sailthru_client.api_post("user", sailthru_parms) except SailthruClientError as exc: error_msg = "Exception attempting to opt-out user {} from Sailthru - {}".format( email, text_type(exc)) log.error(error_msg) raise Exception(error_msg) if not sailthru_response.is_ok(): error = sailthru_response.get_error() error_msg = "Error attempting to opt-out user {} from Sailthru - {}".format( email, error.get_message()) log.error(error_msg) raise Exception(error_msg)
def force_unsubscribe_all(sender, **kwargs): # pylint: disable=unused-argument """ Synchronously(!) unsubscribes the given user from all Sailthru email lists. In the future this could be moved to a Celery task, however this is currently only used as part of user retirement, where we need a very reliable indication of success or failure. Args: email: Email address to unsubscribe new_email (optional): Email address to change 3rd party services to for this user (used in retirement to clear personal information from the service) Returns: None """ email = kwargs.get('email', None) new_email = kwargs.get('new_email', None) if not email: raise TypeError('Expected an email address to unsubscribe, but received None.') email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return sailthru_parms = { "id": email, "optout_email": "all", "fields": {"optout_email": 1} } # If we have a new email address to change to, do that as well if new_email: sailthru_parms["keys"] = { "email": new_email } sailthru_parms["fields"]["keys"] = 1 sailthru_parms["keysconflict"] = "merge" try: sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) sailthru_response = sailthru_client.api_post("user", sailthru_parms) except SailthruClientError as exc: error_msg = "Exception attempting to opt-out user {} from Sailthru - {}".format(email, text_type(exc)) log.error(error_msg) raise Exception(error_msg) if not sailthru_response.is_ok(): error = sailthru_response.get_error() error_msg = "Error attempting to opt-out user {} from Sailthru - {}".format(email, error.get_message()) log.error(error_msg) raise Exception(error_msg)
def add_email_marketing_cookies(sender, response=None, user=None, **kwargs): # pylint: disable=unused-argument """ Signal function for adding any cookies needed for email marketing Args: response: http response object user: The user object for the user being changed Returns: response: http response object with cookie added """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return response post_parms = { 'id': user.email, 'fields': {'keys': 1}, 'vars': {'last_login_date': datetime.datetime.now().strftime("%Y-%m-%d")} } # get sailthru_content cookie to capture usage before logon request = crum.get_current_request() if request: sailthru_content = request.COOKIES.get('sailthru_content') if sailthru_content: post_parms['cookies'] = {'sailthru_content': sailthru_content} try: sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) sailthru_response = \ sailthru_client.api_post("user", post_parms) except SailthruClientError as exc: log.error("Exception attempting to obtain cookie from Sailthru: %s", unicode(exc)) return response if sailthru_response.is_ok(): if 'keys' in sailthru_response.json and 'cookie' in sailthru_response.json['keys']: cookie = sailthru_response.json['keys']['cookie'] response.set_cookie( 'sailthru_hid', cookie, max_age=365 * 24 * 60 * 60 # set for 1 year ) else: log.error("No cookie returned attempting to obtain cookie from Sailthru for %s", user.email) else: error = sailthru_response.get_error() log.error("Error attempting to obtain cookie from Sailthru: %s", error.get_message()) return response
def post(self, request): """ POST /ecommerce/api/v2/assignment-email/bounce Requires a JSON object of the following format: { 'email': [email protected] 'send_id': WFQKQW5K3LBgi0mk 'action': hardbounce 'api_key': 6b805755ce5a23e3c0459aaa598efc56 'sig': 13b3987b656c7771fcac92982fdfb331 } Returns HTTP_200_OK Keys: *email* Email of the customer whose email bounced. *send_id* The unique identifier of the bounced message. *action* hardbounce: Email bounced. *api_key* Key provided by Sailthru. *sig* Hash of API key and all parameter values for the postback call """ secret = settings.SAILTHRU_SECRET key = settings.SAILTHRU_KEY if secret and key: sailthru_client = SailthruClient(key, secret) send_id = request.data.get('send_id') email = request.data.get('email') sig = request.data.get('sig') api_key = request.data.get('api_key') if sailthru_client.receive_hardbounce_post(request.data): try: self.update_email_status(send_id) except (OfferAssignment.DoesNotExist, OfferAssignmentEmailAttempt.DoesNotExist): # Note: Marketing email bounces also come through this code path and # its expected that they would not have a corresponding OfferAssignment pass else: logger.error( '[Offer Assignment] AssignmentEmailBounce: Bounce message could not be verified. ' 'send_id: %s, email: %s, sig: %s, api_key_sailthru: %s, api_key_local: %s ', send_id, email, sig, api_key, key) else: logger.error( '[Offer Assignment] AssignmentEmailBounce: SAILTHRU Parameters not found' ) return Response({}, status=status.HTTP_200_OK)
def update_user(self, sailthru_vars, email, new_user=False, activation=False): """ Adds/updates Sailthru profile information for a user. Args: sailthru_vars(dict): User profile information to pass as 'vars' to Sailthru email(str): User email address new_user(boolean): True if new registration activation(boolean): True if activation request Returns: None """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) try: sailthru_response = sailthru_client.api_post("user", _create_sailthru_user_parm(sailthru_vars, email, new_user, email_config)) except SailthruClientError as exc: log.error("Exception attempting to add/update user %s in Sailthru - %s", email, unicode(exc)) raise self.retry(exc=exc, countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) if not sailthru_response.is_ok(): error = sailthru_response.get_error() # put out error and schedule retry log.error("Error attempting to add/update user in Sailthru: %s", error.get_message()) raise self.retry(countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) # if activating user, send welcome email if activation and email_config.sailthru_activation_template: try: sailthru_response = sailthru_client.api_post("send", {"email": email, "template": email_config.sailthru_activation_template}) except SailthruClientError as exc: log.error("Exception attempting to send welcome email to user %s in Sailthru - %s", email, unicode(exc)) raise self.retry(exc=exc, countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) if not sailthru_response.is_ok(): error = sailthru_response.get_error() # probably a disabled template, just put out error message log.error("Error attempting to send welcome email to user in Sailthru: %s", error.get_message())
def main(): parser = argparse.ArgumentParser(description='Sailthru user import script') parser.add_argument('csv_file_name', help='CSV file name for import.') parser.add_argument('list_name', help='SailThru list name to import users into.') parser.add_argument( 'report_email', help='Email address which will receive report on import completion.') parser.add_argument('sailthru_key', help='Sailthru access key.') parser.add_argument('sailthru_secret', help='Sailthru access secret.') args = parser.parse_args() sailthru_client = SailthruClient(args.sailthru_key, args.sailthru_secret) if args.csv_file_name.find(',') != -1: # handle a comma separated list of CSV files file_list = args.csv_file_name.split(',') for file_name in file_list: upload_csv_to_sailthru(file_name, args.list_name, args.report_email, sailthru_client) else: # handle a single input CSV upload_csv_to_sailthru(args.csv_file_name, args.list_name, args.report_email, sailthru_client) logging.info("Import Complete!")
def get_sailthru_client(site_code): """ Returns a Sailthru client for the specified site. Args: site_code (str): Site for which the client should be configured. Returns: SailthruClient Raises: SailthruNotEnabled: If Sailthru is not enabled for the specified site. ConfigurationError: If either the Sailthru API key or secret are not set for the site. """ # Get configuration config = get_sailthru_configuration(site_code) # Return if Sailthru integration disabled if not config.get('SAILTHRU_ENABLE'): msg = 'Sailthru is not enabled for site {}'.format(site_code) log.debug(msg) raise SailthruNotEnabled(msg) # Make sure key and secret configured key = config.get('SAILTHRU_KEY') secret = config.get('SAILTHRU_SECRET') if not (key and secret): msg = 'Both key and secret are required for site {}'.format(site_code) log.error(msg) raise ConfigurationError(msg) return SailthruClient(key, secret)
def update_course_enrollment(self, email, course_key, mode): """Adds/updates Sailthru when a user adds to cart/purchases/upgrades a course Args: user: current user course_key: course key of course Returns: None """ course_url = build_course_url(course_key) config = EmailMarketingConfiguration.current() try: sailthru_client = SailthruClient(config.sailthru_key, config.sailthru_secret) except: return send_template = config.sailthru_enroll_template cost_in_cents = 0 if not update_unenrolled_list(sailthru_client, email, course_url, False): schedule_retry(self, config) course_data = _get_course_content(course_key, course_url, sailthru_client, config) item = _build_purchase_item(course_key, course_url, cost_in_cents, mode, course_data) options = {} if send_template: options['send_template'] = send_template if not _record_purchase(sailthru_client, email, item, options): schedule_retry(self, config)
def main(argv): args = get_args(argv) # connect to Sailthru sc = SailthruClient(args.sailthru_key, args.sailthru_secret) # Process 'list' command if args.command == 'list': process_list(sc) elif args.command == 'clear': process_clear(sc, False) elif args.command == 'cleanup': process_clear(sc, True) elif args.command == 'load': process_load(args, sc, args.lms_url, None) elif args.command == 'batch': if not args.email_report: logger.error("email_report option required with batch option.") exit(1) with tempfile.NamedTemporaryFile(delete=False) as tmp: process_load(args, None, args.lms_url, tmp) tmp.close() upload_to_sailthru(tmp.name, args.email_report, sc) os.unlink(tmp.name) elif args.command == 'test': process_load(args, None, args.lms_url, None)
def main(argv): args = get_args(argv) user_data = get_list_of_inactive_users(args) logger.info("Total users are: %s." %len(user_data)) sailthru_client = SailthruClient(args.sailthru_key, args.sailthru_secret) update_user_on_sailthru(users_data=user_data, client=sailthru_client) logger.info("All users are updated!")
def add_email_marketing_cookies(sender, response=None, user=None, **kwargs): # pylint: disable=unused-argument """ Signal function for adding any cookies needed for email marketing Args: response: http response object user: The user object for the user being changed Returns: response: http response object with cookie added """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return response try: sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) sailthru_response = \ sailthru_client.api_post("user", {'id': user.email, 'fields': {'keys': 1}, 'vars': {'last_login_date': datetime.datetime.now().strftime("%Y-%m-%d")}}) except SailthruClientError as exc: log.error("Exception attempting to obtain cookie from Sailthru: %s", unicode(exc)) return response if sailthru_response.is_ok(): if 'keys' in sailthru_response.json and 'cookie' in sailthru_response.json['keys']: cookie = sailthru_response.json['keys']['cookie'] response.set_cookie( 'sailthru_hid', cookie, max_age=365 * 24 * 60 * 60 # set for 1 year ) else: log.error("No cookie returned attempting to obtain cookie from Sailthru for %s", user.email) else: error = sailthru_response.get_error() log.error("Error attempting to obtain cookie from Sailthru: %s", error.get_message()) return response
def get_email_cookies_via_sailthru(self, user_email, post_parms): """ Adds/updates Sailthru cookie information for a new user. Args: post_parms(dict): User profile information to pass as 'vars' to Sailthru Returns: cookie(str): cookie fetched from Sailthru """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return None try: sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) log.info( u'Sending to Sailthru the user interest cookie [%s] for user [%s]', post_parms.get('cookies', ''), user_email) sailthru_response = sailthru_client.api_post("user", post_parms) except SailthruClientError as exc: log.error(u"Exception attempting to obtain cookie from Sailthru: %s", six.text_type(exc)) raise SailthruClientError if sailthru_response.is_ok(): if 'keys' in sailthru_response.json and 'cookie' in sailthru_response.json[ 'keys']: cookie = sailthru_response.json['keys']['cookie'] return cookie else: log.error( u"No cookie returned attempting to obtain cookie from Sailthru for %s", user_email) else: error = sailthru_response.get_error() # generally invalid email address log.info(u"Error attempting to obtain cookie from Sailthru: %s", error.get_message()) return None
def force_unsubscribe_all(sender, **kwargs): # pylint: disable=unused-argument """ Synchronously(!) unsubscribes the given user from all Sailthru email lists. In the future this could be moved to a Celery task, however this is currently only used as part of user retirement, where we need a very reliable indication of success or failure. Args: user(User): Django model of type returned from get_user_model() Returns: None """ user = kwargs.get('user', None) if not user: raise TypeError('Expected a User type, but received None.') email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return sailthru_parms = {"id": user.email, "keys": {"optout_email": "all"}} try: sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) sailthru_response = sailthru_client.api_post("user", sailthru_parms) except SailthruClientError as exc: error_msg = "Exception attempting to opt-out user %s from Sailthru - %s" % ( user.email, text_type(exc)) log.error(error_msg) raise Exception(error_msg) if not sailthru_response.is_ok(): error = sailthru_response.get_error() error_msg = "Error attempting to opt-out user %s from Sailthru - %s" % ( user.email, error.get_message()) log.error(error_msg) raise Exception(error_msg)
def get_email_cookies_via_sailthru(self, user_email, post_parms): """ Adds/updates Sailthru cookie information for a new user. Args: post_parms(dict): User profile information to pass as 'vars' to Sailthru Returns: cookie(str): cookie fetched from Sailthru """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return None try: sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) log.info( 'Sending to Sailthru the user interest cookie [%s] for user [%s]', post_parms.get('cookies', ''), user_email ) sailthru_response = sailthru_client.api_post("user", post_parms) except SailthruClientError as exc: log.error("Exception attempting to obtain cookie from Sailthru: %s", unicode(exc)) raise SailthruClientError if sailthru_response.is_ok(): if 'keys' in sailthru_response.json and 'cookie' in sailthru_response.json['keys']: cookie = sailthru_response.json['keys']['cookie'] return cookie else: log.error("No cookie returned attempting to obtain cookie from Sailthru for %s", user_email) else: error = sailthru_response.get_error() # generally invalid email address log.info("Error attempting to obtain cookie from Sailthru: %s", error.get_message()) return None
def main(argv): args = get_args(argv) # connect to Sailthru sc = SailthruClient(args.sailthru_key, args.sailthru_secret) # Process 'list' command if args.command == 'list': process_list(sc) elif args.command == 'clear': process_clear(sc) elif args.command == 'load': process_load(args, sc, args.lms_url, False) elif args.command == 'test': process_load(args, sc, args.lms_url, True)
def main(): parser = argparse.ArgumentParser(description='Sailthru order import script') parser.add_argument('file_names', help='Comma separated file name list for import.') parser.add_argument('report_email', help='Email address which will receive report on import completion.') parser.add_argument('sailthru_key', help='Sailthru access key.') parser.add_argument('sailthru_secret', help='Sailthru access secret.') args = parser.parse_args() sailthru_client = SailthruClient(args.sailthru_key, args.sailthru_secret) if args.file_names.find(',') != -1: # handle a comma separated list of json files file_list = args.file_names.split(',') for file_name in file_list: upload_to_sailthru(file_name, args.report_email, sailthru_client) else: # handle a single input CSV upload_to_sailthru(args.file_names, args.report_email, sailthru_client) logger.info("Import Complete!")
def update_course_enrollment(self, email, course_key, mode, site=None): """Adds/updates Sailthru when a user adds to cart/purchases/upgrades a course Args: email: email address of enrolled user course_key: course key of course mode: mode user is enrolled in site: site where user enrolled Returns: None """ # do not add user if registered at a white label site if not is_default_site(site): return course_url = build_course_url(course_key) config = EmailMarketingConfiguration.current() try: sailthru_client = SailthruClient(config.sailthru_key, config.sailthru_secret) except: return send_template = config.sailthru_enroll_template cost_in_cents = 0 if not update_unenrolled_list(sailthru_client, email, course_url, False): schedule_retry(self, config) course_data = _get_course_content(course_key, course_url, sailthru_client, config) item = _build_purchase_item(course_key, course_url, cost_in_cents, mode, course_data) options = {} if send_template: options['send_template'] = send_template if not _record_purchase(sailthru_client, email, item, options): schedule_retry(self, config)
class SailthruApi(object): """ Sailthru API client used to make all Sailthru calls. """ def __init__(self, sailthru_key, sailthru_secret): """ Create a Sailthru client using credentials. """ self._sailthru_client = SailthruClient(sailthru_key, sailthru_secret) @backoff.on_exception(backoff.expo, SailthruClientError, max_tries=MAX_ATTEMPTS) def delete_user(self, learner): """ Delete a user from Sailthru using their email address. """ email = learner.get('original_email', None) if not email: raise TypeError( 'Expected an email address for user to delete, but received None.' ) sailthru_response = self._sailthru_client.api_delete( "user", {'id': email}) if not sailthru_response.is_ok(): error = sailthru_response.get_error() if SAILTHRU_ERROR_NOT_FOUND in error.get_message(): LOG.info( "No action taken because no user was found in Sailthru.") else: error_msg = u"Error attempting to delete user from Sailthru - {}".format( error.get_message()).encode('utf-8') LOG.error(error_msg) raise Exception(error_msg) LOG.info("User successfully deleted from Sailthru.")
# -*- coding: utf-8 -*- from sailthru.sailthru_client import SailthruClient from sailthru.sailthru_response import SailthruResponseError from sailthru.sailthru_error import SailthruClientError api_key = 'API_KEY' api_secret = 'SUPER_SECRET' sailthru_client = SailthruClient(api_key, api_secret) try: response = sailthru_client.api_get("user", {"id": "*****@*****.**"}) if response.is_ok(): body = response.get_body() # handle body which is of type dictionary print body else: error = response.get_error() print "Error: " + error.get_message() print "Status Code: " + str(response.get_status_code()) print "Error Code: " + str(error.get_error_code()) except SailthruClientError, e: # Handle exceptions print "Exception" print e
import sys import json from sailthru.sailthru_client import SailthruClient from sailthru.sailthru_response import SailthruResponseError from sailthru.sailthru_error import SailthruClientError import boto import boto.s3 from secrets import * from boto.s3.connection import OrdinaryCallingFormat, S3Connection api_key = ST_API_KEY api_secret = ST_API_SECRET sailthru_client = SailthruClient(api_key, api_secret) def get_newsletter_count_sailthru(newsletter): try: response = sailthru_client.api_get("stats", { "stat": "list", "list": newsletter, "date": "2017-03-15" }) if response.is_ok(): try: body = response.get_body() list_data = body return list_data
# -*- coding: utf-8 -*- from sailthru.sailthru_client import SailthruClient from sailthru.sailthru_response import SailthruResponseError from sailthru.sailthru_error import SailthruClientError api_key = 'API_KEY' api_secret = 'SUPER_SECRET' sailthru_client = SailthruClient(api_key, api_secret) try: template = "not_so_useful_template" response = sailthru_client.api_delete("template", {"template": template}) if response.is_ok(): body = response.get_body() # handle body which is of type dictionary print(body) else: error = response.get_error() print("Error: " + error.get_message()) print("Status Code: " + str(response.get_status_code())) print("Error Code: " + str(error.get_error_code())) except SailthruClientError as e: # Handle exceptions print("Exception") print(e)
def __init__(self, sailthru_key, sailthru_secret, content_url_root): self.sailthru_client = SailthruClient(sailthru_key, sailthru_secret) self.content_url_root = content_url_root
class SailthruApiService(object): """The service to interface with Sailthru API""" def __init__(self, sailthru_key, sailthru_secret, content_url_root): self.sailthru_client = SailthruClient(sailthru_key, sailthru_secret) self.content_url_root = content_url_root def list(self, list_size=1000): sailthru_content_list = [] response = self.sailthru_client.api_get('content', {'items': list_size}) if not response.is_ok(): logging.error( "Error code %d connecting to Sailthru content api: %s", response.json['error'], response.json['errormsg'] ) else: for body in response.json['content']: logging.info(body) sailthru_content_list.append(body) return sailthru_content_list def _upload_batch_file(self, filepath, report_email=None): """Use Sailthru job API to upload all content as a batch job""" logging.info("Uploading %s" % filepath) request_data = { 'job': 'content_update', 'file': filepath, 'report_email': report_email } response = self.sailthru_client.api_post('job', request_data, {'file': 1}) if response.is_ok(): job_id = response.get_body().get("job_id") logging.info("Import job started on SailThru - JOB ID: " + job_id) # Keeping checking status until we find out that it's done while True: logging.info("waiting for import to complete...") time.sleep(10) response = self.sailthru_client.api_get('job', {'job_id': job_id}) if response.get_body().get("status") == "completed": return else: error = response.get_error() logging.error("Error: " + error.get_message()) logging.error("Status Code: " + str(response.get_status_code())) logging.error("Error Code: " + str(error.get_error_code())) def upload(self, library_items, report_email=None): if not library_items: return with tempfile.NamedTemporaryFile(delete=False) as tmp_file: for item in library_items: json.dump(item, tmp_file) tmp_file.write('\n') tmp_file.close() self._upload_batch_file(tmp_file.name, report_email) os.unlink(tmp_file.name) def clear(self): while True: response = self.sailthru_client.api_get('content', {'items': 4000}) if not response.is_ok(): logging.error( "Error code %d connecting to Sailthru content api: %s", response.json['error'], response.json['errormsg'] ) return sailthru_content = response.json['content'] if not sailthru_content: logging.info('Content cleared') return for body in sailthru_content: item_key = body.get('url') if item_key: response = self.sailthru_client.api_delete('content', {'url': item_key}) if response.is_ok(): logging.info("content item %s deleted", item_key) else: logging.info("content item %s delete encountered errors", item_key)
def update_course_enrollment(self, email, course_url, event, mode, course_id=None, message_id=None): # pylint: disable=unused-argument """ Adds/updates Sailthru when a user enrolls/unenrolls/adds to cart/purchases/upgrades a course Args: email(str): The user's email address course_url(str): Course home page url event(str): event type mode(str): enroll mode (audit, verification, ...) unit_cost: cost if purchase event course_id(str): course run id currency(str): currency if purchase event - currently ignored since Sailthru only supports USD Returns: None The event can be one of the following: EnrollStatusChange.enroll A free enroll (mode=audit or honor) EnrollStatusChange.unenroll An unenroll EnrollStatusChange.upgrade_start A paid upgrade added to cart - ignored EnrollStatusChange.upgrade_complete A paid upgrade purchase complete - ignored EnrollStatusChange.paid_start A non-free course added to cart - ignored EnrollStatusChange.paid_complete A non-free course purchase complete - ignored """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return # Use event type to figure out processing required unenroll = False send_template = None cost_in_cents = 0 if event == EnrollStatusChange.enroll: send_template = email_config.sailthru_enroll_template # set cost so that Sailthru recognizes the event cost_in_cents = email_config.sailthru_enroll_cost elif event == EnrollStatusChange.unenroll: # unenroll - need to update list of unenrolled courses for user in Sailthru unenroll = True else: # All purchase events should be handled by ecommerce, so ignore return sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) # update the "unenrolled" course array in the user record on Sailthru if not _update_unenrolled_list(sailthru_client, email, course_url, unenroll): raise self.retry(countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) # if there is a cost, call Sailthru purchase api to record if cost_in_cents: # get course information if configured and appropriate event course_data = {} if email_config.sailthru_get_tags_from_sailthru: course_data = _get_course_content(course_url, sailthru_client, email_config) # build item description item = _build_purchase_item(course_id, course_url, cost_in_cents, mode, course_data) # build purchase api options list options = {} # add appropriate send template if send_template: options['send_template'] = send_template if not _record_purchase(sailthru_client, email, item, message_id, options): raise self.retry(countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries)
# -*- coding: utf-8 -*- from sailthru.sailthru_client import SailthruClient from sailthru.sailthru_response import SailthruResponseError from sailthru.sailthru_error import SailthruClientError api_key = 'API_KEY' api_secret = 'SUPER_SECRET' sailthru_client = SailthruClient(api_key, api_secret) try: template = "not_so_useful_template" response = sailthru_client.api_delete("template", {"template": template}) if response.is_ok(): body = response.get_body() # handle body which is of type dictionary print body else: error = response.get_error() print "Error: " + error.get_message() print "Status Code: " + str(response.get_status_code()) print "Error Code: " + str(error.get_error_code()) except SailthruClientError, e: # Handle exceptions print "Exception" print e
from sailthru.sailthru_client import SailthruClient api_key = "replace-with-your-api-key" api_secret = "replace-with-your-api-secret" api_url = "http://api.sailthru.com" # optional sc = SailthruClient(api_key, api_secret, api_url) # GET /user response = sc.api_get('user', {'email': '*****@*****.**'}) print "is_ok: " + str(response.is_ok()) print "body: " + str(response.get_body()) print "response: " + str(response.get_response()) print "status_code: " + str(response.get_status_code()) print "error: " + str(response.get_error())
class SailthruApiService(object): """The service to interface with Sailthru API""" def __init__(self, sailthru_key, sailthru_secret, content_url_root): self.sailthru_client = SailthruClient(sailthru_key, sailthru_secret) self.content_url_root = content_url_root def list(self, list_size=1000): sailthru_content_list = [] response = self.sailthru_client.api_get('content', {'items': list_size}) if not response.is_ok(): logging.error( "Error code %d connecting to Sailthru content api: %s", response.json['error'], response.json['errormsg']) raise RuntimeError('Failed to connect with Sailthru API') else: for body in response.json['content']: logging.info(body) sailthru_content_list.append(body) return sailthru_content_list def _upload_batch_file(self, filepath, report_email=None): """Use Sailthru job API to upload all content as a batch job""" logging.info("Uploading %s" % filepath) request_data = { 'job': 'content_update', 'file': filepath, 'report_email': report_email } response = self.sailthru_client.api_post('job', request_data, {'file': 1}) if response.is_ok(): job_id = response.get_body().get("job_id") logging.info("Import job started on SailThru - JOB ID: " + job_id) # Keeping checking status until we find out that it's done while True: logging.info("waiting for import to complete...") time.sleep(10) response = self.sailthru_client.api_get( 'job', {'job_id': job_id}) if response.get_body().get("status") == "completed": return else: error = response.get_error() logging.error("Error: " + error.get_message()) logging.error("Status Code: " + str(response.get_status_code())) logging.error("Error Code: " + str(error.get_error_code())) raise RuntimeError('Failed to connect with Sailthru API') def upload(self, library_items, report_email=None): if not library_items: return with tempfile.NamedTemporaryFile(delete=False, mode='w+t') as tmp_file: for item in library_items: json.dump(item, tmp_file) tmp_file.write('\n') tmp_file.close() self._upload_batch_file(tmp_file.name, report_email) os.unlink(tmp_file.name) def clear(self): while True: response = self.sailthru_client.api_get('content', {'items': 4000}) if not response.is_ok(): logging.error( "Error code %d connecting to Sailthru content api: %s", response.json['error'], response.json['errormsg']) raise RuntimeError('Failed to connect with Sailthru API') sailthru_content = response.json['content'] if not sailthru_content: logging.info('Content cleared') return for body in sailthru_content: item_key = body.get('url') if item_key: response = self.sailthru_client.api_delete( 'content', {'url': item_key}) if response.is_ok(): logging.info("content item %s deleted", item_key) else: logging.info( "content item %s delete encountered errors", item_key)
def update_user(self, sailthru_vars, email, new_user=False, activation=False): """ Adds/updates Sailthru profile information for a user. Args: sailthru_vars(dict): User profile information to pass as 'vars' to Sailthru email(str): User email address new_user(boolean): True if new registration activation(boolean): True if activation request Returns: None """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) try: sailthru_response = sailthru_client.api_post( "user", _create_sailthru_user_parm(sailthru_vars, email, new_user, email_config)) except SailthruClientError as exc: log.error( "Exception attempting to add/update user %s in Sailthru - %s", email, unicode(exc)) raise self.retry(exc=exc, countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) if not sailthru_response.is_ok(): error = sailthru_response.get_error() # put out error and schedule retry log.error("Error attempting to add/update user in Sailthru: %s", error.get_message()) raise self.retry(countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) # if activating user, send welcome email if activation and email_config.sailthru_activation_template: try: sailthru_response = sailthru_client.api_post( "send", { "email": email, "template": email_config.sailthru_activation_template }) except SailthruClientError as exc: log.error( "Exception attempting to send welcome email to user %s in Sailthru - %s", email, unicode(exc)) raise self.retry(exc=exc, countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) if not sailthru_response.is_ok(): error = sailthru_response.get_error() # probably a disabled template, just put out error message log.error( "Error attempting to send welcome email to user in Sailthru: %s", error.get_message())
def update_course_enrollment(self, email, course_url, event, mode, unit_cost=None, course_id=None, currency=None, message_id=None): # pylint: disable=unused-argument """ Adds/updates Sailthru when a user enrolls/unenrolls/adds to cart/purchases/upgrades a course Args: email(str): The user's email address course_url(str): Course home page url event(str): event type mode(object): enroll mode (audit, verification, ...) unit_cost: cost if purchase event course_id(CourseKey): course id currency(str): currency if purchase event - currently ignored since Sailthru only supports USD Returns: None The event can be one of the following: EnrollStatusChange.enroll A free enroll (mode=audit) EnrollStatusChange.unenroll An unenroll EnrollStatusChange.upgrade_start A paid upgrade added to cart EnrollStatusChange.upgrade_complete A paid upgrade purchase complete EnrollStatusChange.paid_start A non-free course added to cart EnrollStatusChange.paid_complete A non-free course purchase complete """ email_config = EmailMarketingConfiguration.current() if not email_config.enabled: return course_id_string = course_id.to_deprecated_string() # Use event type to figure out processing required new_enroll = unenroll = fetch_tags = False incomplete = send_template = None if unit_cost: cost_in_cents = unit_cost * 100 if event == EnrollStatusChange.enroll: # new enroll for audit (no cost) new_enroll = True fetch_tags = True send_template = email_config.sailthru_enroll_template # set cost of $1 so that Sailthru recognizes the event cost_in_cents = email_config.sailthru_enroll_cost elif event == EnrollStatusChange.unenroll: # unenroll - need to update list of unenrolled courses for user in Sailthru unenroll = True elif event == EnrollStatusChange.upgrade_start: # add upgrade to cart incomplete = 1 elif event == EnrollStatusChange.paid_start: # add course purchase (probably 'honor') to cart incomplete = 1 elif event == EnrollStatusChange.upgrade_complete: # upgrade complete fetch_tags = True send_template = email_config.sailthru_upgrade_template elif event == EnrollStatusChange.paid_complete: # paid course purchase complete new_enroll = True fetch_tags = True send_template = email_config.sailthru_purchase_template sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) # update the "unenrolled" course array in the user record on Sailthru if new enroll or unenroll if new_enroll or unenroll: if not _update_unenrolled_list(sailthru_client, email, course_url, unenroll): raise self.retry(countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries) # if there is a cost, call Sailthru purchase api to record if cost_in_cents: # get course information if configured and appropriate event if fetch_tags and email_config.sailthru_get_tags_from_sailthru: course_data = _get_course_content(course_url, sailthru_client, email_config) else: course_data = {} # build item description item = _build_purchase_item(course_id_string, course_url, cost_in_cents, mode, course_data, course_id) # build purchase api options list options = {} if incomplete and email_config.sailthru_abandoned_cart_template: options['reminder_template'] = email_config.sailthru_abandoned_cart_template options['reminder_time'] = "+{} minutes".format(email_config.sailthru_abandoned_cart_delay) # add appropriate send template if send_template: options['send_template'] = send_template if not _record_purchase(sailthru_client, email, item, incomplete, message_id, options): raise self.retry(countdown=email_config.sailthru_retry_interval, max_retries=email_config.sailthru_max_retries)
# -*- coding: utf-8 -*- from sailthru.sailthru_client import SailthruClient from sailthru.sailthru_response import SailthruResponseError from sailthru.sailthru_error import SailthruClientError api_key = 'API_KEY' api_secret = 'SUPER_SECRET' sailthru_client = SailthruClient(api_key, api_secret) try: data = { "id": "*****@*****.**", "vars": { "name": "Prajwal Tuladhar", "address": { "city": "New York", "state": "NY", "zip": 11372 }, "preferred_login": "******", "has_used_smartphone": true }, "keys": { "fb": "infynyxx", "twitter": "infynyxx" } } response = sailthru_client.api_post("user", data) if response.is_ok():
# -*- coding: utf-8 -*- from sailthru.sailthru_client import SailthruClient from sailthru.sailthru_response import SailthruResponseError from sailthru.sailthru_error import SailthruClientError api_key = 'API_KEY' api_secret = 'SUPER_SECRET' sailthru_client = SailthruClient(api_key, api_secret) try: response = sailthru_client.api_get("user", {"id": "*****@*****.**"}) if response.is_ok(): body = response.get_body() # handle body which is of type dictionary print(body) else: error = response.get_error() print("Error: " + error.get_message()) print("Status Code: " + str(response.get_status_code())) print("Error Code: " + str(error.get_error_code())) except SailthruClientError as e: # Handle exceptions print("Exception") print(e)
__author__ = 'brucepannaman' from sailthru.sailthru_client import SailthruClient from sailthru.sailthru_response import SailthruResponseError from sailthru.sailthru_error import SailthruClientError import datetime import psycopg2 import csv import tinys3 import os api_key = '***' api_secret = '***' sailthru_client = SailthruClient(api_key, api_secret) # Validate if the connection to Sailthru works try: response = sailthru_client.api_get("user", {"id": "*****@*****.**"}) except SailthruClientError: print SailthruResponseError # Log if the connection is live if response.is_ok(): body = response.get_body() print "Test went ok" # This is the final array of each day that will be written into the db output_array = []
import os from sailthru_import import sailthru_import from sailthru.sailthru_client import SailthruClient sailthru_client = SailthruClient(os.environ['SAILTHRU_API_KEY'], os.environ['SAILTHRU_API_SECRET']) def get_user(email): try: user_response = sailthru_client.api_get("user", {"id": email}) if user_response.is_ok(): body = user_response.get_body() # handle body which is of type dictionary print (body) if body['keys']['sid'] != '': print ("User exists!") else: error = user_response.get_error() print ("Error: " + error.get_message()) print ("Status Code: " + str(user_response.get_status_code())) print ("Error Code: " + str(error.get_error_code())) return {body['keys']} def add_user_to_sailthru(user): data = {"id": user['Email Address']} data['name'] = user['Name'] data['vars'] = user
def __init__(self, sailthru_key, sailthru_secret): """ Create a Sailthru client using credentials. """ self._sailthru_client = SailthruClient(sailthru_key, sailthru_secret)