def _unsubscribe(request): email = request.POST["data[email]"] try: email_address = EmailAddress.objects.get(email=email) user = email_address.user user_exists = True primary_email = find_best_email_for_user(user) # If the user exists and the subscription update was related to their primary # email address, update their marketing contact preference. (We don't want to # update the preference if their non-primary email address was unsubscribed, # because that won't really reflect the actual state of their preference.) if "email" in user.settings and primary_email and primary_email.email == email: user.settings["email"]["marketing"] = False user.save() except EmailAddress.DoesNotExist: user_exists = False primary_email = False influx_metric( "mailchimp_webhook_request", {"value": 1}, reason=request.POST.get("data[reason]"), type="unsubscribe", primary_email=primary_email, user_exists=user_exists )
def _subscribe(request): email = request.POST["data[email]"] try: email_address = EmailAddress.objects.get(email=email) user = email_address.user user_exists = True primary_email = find_best_email_for_user(user) # If the user exists and the subscription webhook was about their primary email, # update their marketing contact preference to reflect that. if primary_email and primary_email.email == email: if "email" not in user.settings: user.settings["email"] = {"marketing": True} else: user.settings["email"]["marketing"] = True user.save() except EmailAddress.DoesNotExist: user_exists = False primary_email = False influx_metric( "mailchimp_webhook_request", {"value": 1}, type="subscribe", primary_email=primary_email, user_exists=user_exists )
def test_find_best_email_for_user_primary(user): EmailAddress.objects.add_email(None, user, "*****@*****.**") email2 = EmailAddress.objects.add_email(None, user, "*****@*****.**") email2.set_as_primary() assert find_best_email_for_user(user) == email2
def post(self, request): marketing_prefs = request.POST.get("marketing", "") == "on" request.user.settings["email"] = { "marketing": marketing_prefs, "updated": timezone.now().isoformat(), } request.user.save() try: client = get_mailchimp_client() email = find_best_email_for_user(request.user) client.lists.members.create_or_update( settings.MAILCHIM_LIST_KEY_ID, get_subscriber_hash(email.email), { "email_address": email.email, "status_if_new": get_mailchimp_subscription_status(request.user) }) except Exception as e: log.warning("Failed to contact MailChimp API: %s" % e) influx_metric("mailchimp_request_failures", {"count": 1}) messages.info(request, _("Your email preferences have been saved.")) return redirect(self.success_url)
def _process_page(self, page, options): user_tags = [] for user in page: pct_before = self._percent(self.user_count, self.total_users) self.user_count += 1 pct_after = self._percent(self.user_count, self.total_users) if pct_before != pct_after: print(f"Working... {pct_after}% complete.", flush=True) email = find_best_email_for_user(user) if email: tags_to_add = [] tags_to_remove = [] for tag in TAGS: if tag.should_apply_to(user): tags_to_add.append(tag) else: tags_to_remove.append(tag) user_tags.append((user, email, tags_to_add, tags_to_remove)) # After we've read all the data from the page, go back and make modifications; this # part clears the prefetch cache so it has to happen as a second pass. with transaction.atomic(): for user, email, tags_to_add, tags_to_remove in user_tags: mailchimp_tags_to_add = [] mailchimp_tags_to_remove = [] needs_publish = False for tag in tags_to_add: if tag.add_user_to_tag_group(user): mailchimp_tags_to_add.append(tag) needs_publish = True for tag in tags_to_remove: if tag.remove_user_from_tag_group(user): mailchimp_tags_to_remove.append(tag) needs_publish = True if needs_publish: self.users_with_tag_changes += 1 if options["publish_remote"]: self._publish_tag_changes(user, email.email, mailchimp_tags_to_add, mailchimp_tags_to_remove, verbose=options["verbose"])
def _update_mailchimp_tags_for_premium_subscriber(user): email = find_best_email_for_user(user) if email: tag = PremiumSubscriberTag() if tag.should_apply_to(user) and tag.add_user_to_tag_group(user): client = get_mailchimp_client() list_key_id = settings.MAILCHIMP_LIST_KEY_ID email_hash = get_subscriber_hash(email.email) # At this point we have no idea whether the user's email address is already # registered with MailChimp, so do a defensive create-or-update to make sure # it's on the list before we give them the premium tag. try: client.lists.members.create_or_update( list_key_id, email_hash, { "email_address": email.email, "status_if_new": get_mailchimp_subscription_status(user), }) influx_metric("mailchimp_requests", {"count": 1}, method="create_or_update") # ...then assign the premium tag. client.lists.members.tags.add(list_key_id, email_hash, tag.name) influx_metric("mailchimp_requests", {"count": 1}, method="add_tags") except Exception as e: log.warning("Failed to contact MailChimp API: %s" % e) influx_metric("mailchimp_request_failures", {"count": 1})
def test_find_best_email_for_user_no_primary(user): email1 = EmailAddress.objects.add_email(None, user, "*****@*****.**") EmailAddress.objects.add_email(None, user, "*****@*****.**") assert find_best_email_for_user(user) == email1
def test_find_best_email_for_user_no_emails(user): assert find_best_email_for_user(user) is None
def post(self, request): marketing_prefs = request.POST.get("marketing", "") == "on" client = get_mailchimp_client() try: request.user.settings["email"] = { "marketing": marketing_prefs, "updated": timezone.now().isoformat(), } status = get_mailchimp_subscription_status(request.user) email = find_best_email_for_user(request.user) try: client.lists.members.create_or_update( settings.MAILCHIMP_LIST_KEY_ID, get_subscriber_hash(email.email), { "email_address": email.email, "status_if_new": status, "status": status }) except MailChimpError as e: # The request to Mailchimp may fail if the user unsubscribed via the # Mailchimp interface (through a link in an email footer, e.g.). In this # case, they can only resubscribe through a confirmation email. Setting the # user's status to 'pending' will trigger the confirmation email to be sent. args = e.args[0] if (args.get("status") == 400 and args.get("title") == "Member In Compliance State"): client.lists.members.update( settings.MAILCHIMP_LIST_KEY_ID, get_subscriber_hash(email.email), { "email_address": email.email, "status": "pending" }) influx_metric("mailchimp_requests", {"count": 1}, method="update") return self._redirect_with_message( request, _("Check your inbox! We've sent an email to confirm your subscription preferences." )) else: self._log_mailchimp_error(e) return self._redirect_with_message( request, _("Failed to save your email preferences. Please try again later!" )) except Exception as e: self._log_mailchimp_error(e) return self._redirect_with_message( request, _("Failed to save your email preferences. Please try again later!" )) # Only save the user record if we were actually able to sync the marketing # preferences with Mailchimp. request.user.save() influx_metric("mailchimp_requests", {"count": 1}, method="create_or_update") return self._redirect_with_message( request, _("Your email preferences have been saved."))