Merge pull request #6073 from edx/sanchez/add_email_optin_api_endpoint
Create new API endpoint for email optin
This commit is contained in:
@@ -5,11 +5,16 @@ but does NOT include basic account information such as username, password, and
|
||||
email address.
|
||||
|
||||
"""
|
||||
import datetime
|
||||
from django.conf import settings
|
||||
from django.db import IntegrityError
|
||||
import logging
|
||||
from pytz import UTC
|
||||
|
||||
|
||||
from user_api.models import User, UserProfile, UserPreference
|
||||
from user_api.models import User, UserProfile, UserPreference, UserOrgTag
|
||||
from user_api.helpers import intercept_errors
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class ProfileRequestError(Exception):
|
||||
""" The request to the API was not valid. """
|
||||
@@ -155,3 +160,45 @@ def update_preferences(username, **kwargs):
|
||||
else:
|
||||
for key, value in kwargs.iteritems():
|
||||
UserPreference.set_preference(user, key, value)
|
||||
|
||||
|
||||
@intercept_errors(ProfileInternalError, ignore_errors=[ProfileRequestError])
|
||||
def update_email_opt_in(username, org, optin):
|
||||
"""Updates a user's preference for receiving org-wide emails.
|
||||
|
||||
Sets a User Org Tag defining the choice to opt in or opt out of organization-wide
|
||||
emails.
|
||||
|
||||
Args:
|
||||
username (str): The user to set a preference for.
|
||||
org (str): The org is used to determine the organization this setting is related to.
|
||||
optin (boolean): True if the user is choosing to receive emails for this organization. If the user is not
|
||||
the correct age to receive emails, email-optin is set to False regardless.
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Raises:
|
||||
ProfileUserNotFound: Raised when the username specified is not associated with a user.
|
||||
|
||||
"""
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
raise ProfileUserNotFound
|
||||
|
||||
profile = UserProfile.objects.get(user=user)
|
||||
of_age = (
|
||||
profile.year_of_birth is None or # If year of birth is not set, we assume user is of age.
|
||||
datetime.datetime.now(UTC).year - profile.year_of_birth >= # pylint: disable=maybe-no-member
|
||||
getattr(settings, 'EMAIL_OPTIN_MINIMUM_AGE', 13)
|
||||
)
|
||||
|
||||
try:
|
||||
preference, _ = UserOrgTag.objects.get_or_create(
|
||||
user=user, org=org, key='email-optin'
|
||||
)
|
||||
preference.value = str(optin and of_age)
|
||||
preference.save()
|
||||
except IntegrityError as err:
|
||||
log.warn(u"Could not update organization wide preference due to IntegrityError: {}".format(err.message))
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Tests for the profile API. """
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from django.test import TestCase
|
||||
import ddt
|
||||
from django.test.utils import override_settings
|
||||
from nose.tools import raises
|
||||
from dateutil.parser import parse as parse_datetime
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
import datetime
|
||||
|
||||
from user_api.api import account as account_api
|
||||
from user_api.api import profile as profile_api
|
||||
from user_api.models import UserProfile
|
||||
from user_api.models import UserProfile, UserOrgTag
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -94,6 +98,84 @@ class ProfileApiTest(TestCase):
|
||||
preferences = profile_api.preference_info(self.USERNAME)
|
||||
self.assertEqual(preferences['preference_key'], 'preference_value')
|
||||
|
||||
@ddt.data(
|
||||
# Check that a 27 year old can opt-in
|
||||
(27, True, u"True"),
|
||||
|
||||
# Check that a 32-year old can opt-out
|
||||
(32, False, u"False"),
|
||||
|
||||
# Check that someone 13 years old can opt-in
|
||||
(13, True, u"True"),
|
||||
|
||||
# Check that someone 12 years old cannot opt-in
|
||||
(12, True, u"False")
|
||||
)
|
||||
@ddt.unpack
|
||||
@override_settings(EMAIL_OPTIN_MINIMUM_AGE=13)
|
||||
def test_update_email_optin(self, age, option, expected_result):
|
||||
# Create the course and account.
|
||||
course = CourseFactory.create()
|
||||
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
|
||||
|
||||
# Set year of birth
|
||||
user = User.objects.get(username=self.USERNAME)
|
||||
profile = UserProfile.objects.get(user=user)
|
||||
year_of_birth = datetime.datetime.now().year - age # pylint: disable=maybe-no-member
|
||||
profile.year_of_birth = year_of_birth
|
||||
profile.save()
|
||||
|
||||
profile_api.update_email_opt_in(self.USERNAME, course.id.org, option)
|
||||
result_obj = UserOrgTag.objects.get(user=user, org=course.id.org, key='email-optin')
|
||||
self.assertEqual(result_obj.value, expected_result)
|
||||
|
||||
def test_update_email_optin_no_age_set(self):
|
||||
# Test that the API still works if no age is specified.
|
||||
# Create the course and account.
|
||||
course = CourseFactory.create()
|
||||
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
|
||||
|
||||
user = User.objects.get(username=self.USERNAME)
|
||||
|
||||
profile_api.update_email_opt_in(self.USERNAME, course.id.org, True)
|
||||
result_obj = UserOrgTag.objects.get(user=user, org=course.id.org, key='email-optin')
|
||||
self.assertEqual(result_obj.value, u"True")
|
||||
|
||||
@ddt.data(
|
||||
# Check that a 27 year old can opt-in, then out.
|
||||
(27, True, False, u"False"),
|
||||
|
||||
# Check that a 32-year old can opt-out, then in.
|
||||
(32, False, True, u"True"),
|
||||
|
||||
# Check that someone 13 years old can opt-in, then out.
|
||||
(13, True, False, u"False"),
|
||||
|
||||
# Check that someone 12 years old cannot opt-in, then explicitly out.
|
||||
(12, True, False, u"False")
|
||||
)
|
||||
@ddt.unpack
|
||||
@override_settings(EMAIL_OPTIN_MINIMUM_AGE=13)
|
||||
def test_change_email_optin(self, age, option, second_option, expected_result):
|
||||
# Create the course and account.
|
||||
course = CourseFactory.create()
|
||||
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
|
||||
|
||||
# Set year of birth
|
||||
user = User.objects.get(username=self.USERNAME)
|
||||
profile = UserProfile.objects.get(user=user)
|
||||
year_of_birth = datetime.datetime.now().year - age # pylint: disable=maybe-no-member
|
||||
profile.year_of_birth = year_of_birth
|
||||
profile.save()
|
||||
|
||||
profile_api.update_email_opt_in(self.USERNAME, course.id.org, option)
|
||||
profile_api.update_email_opt_in(self.USERNAME, course.id.org, second_option)
|
||||
|
||||
result_obj = UserOrgTag.objects.get(user=user, org=course.id.org, key='email-optin')
|
||||
self.assertEqual(result_obj.value, expected_result)
|
||||
|
||||
|
||||
|
||||
@raises(profile_api.ProfileUserNotFound)
|
||||
def test_retrieve_and_update_preference_info_no_user(self):
|
||||
preferences = profile_api.preference_info(self.USERNAME)
|
||||
|
||||
@@ -1365,6 +1365,10 @@ BULK_EMAIL_LOG_SENT_EMAILS = False
|
||||
# parallel, and what the SES rate is.
|
||||
BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS = 0.02
|
||||
|
||||
############################# Email Opt In ####################################
|
||||
|
||||
# Minimum age for organization-wide email opt in
|
||||
EMAIL_OPTIN_MINIMUM_AGE = 13
|
||||
|
||||
############################## Video ##########################################
|
||||
|
||||
|
||||
Reference in New Issue
Block a user