Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
0e66baf4
Commit
0e66baf4
authored
May 12, 2016
by
Peter Fogg
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add referral tracking for new registrations.
ECOM-4325
parent
140fd85e
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
144 additions
and
2 deletions
+144
-2
cms/envs/aws.py
+3
-0
cms/envs/common.py
+3
-0
common/djangoapps/student/migrations/0003_auto_20160516_0938.py
+33
-0
common/djangoapps/student/models.py
+44
-0
common/djangoapps/student/tests/test_create_account.py
+19
-0
common/djangoapps/student/tests/tests.py
+24
-1
common/djangoapps/student/views.py
+13
-1
lms/envs/aws.py
+2
-0
lms/envs/common.py
+3
-0
No files found.
cms/envs/aws.py
View file @
0e66baf4
...
...
@@ -415,3 +415,6 @@ if FEATURES.get('CUSTOM_COURSES_EDX'):
# Partner support link for CMS footer
PARTNER_SUPPORT_EMAIL
=
ENV_TOKENS
.
get
(
'PARTNER_SUPPORT_EMAIL'
,
PARTNER_SUPPORT_EMAIL
)
# Affiliate cookie tracking
AFFILIATE_COOKIE_NAME
=
ENV_TOKENS
.
get
(
'AFFILIATE_COOKIE_NAME'
,
AFFILIATE_COOKIE_NAME
)
cms/envs/common.py
View file @
0e66baf4
...
...
@@ -1193,3 +1193,6 @@ USERNAME_PATTERN = r'(?P<username>[\w.@+-]+)'
# Partner support link for CMS footer
PARTNER_SUPPORT_EMAIL
=
''
# Affiliate cookie tracking
AFFILIATE_COOKIE_NAME
=
'affiliate_id'
common/djangoapps/student/migrations/0003_auto_20160516_0938.py
0 → 100644
View file @
0e66baf4
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
import
django.utils.timezone
from
django.conf
import
settings
import
model_utils.fields
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
migrations
.
swappable_dependency
(
settings
.
AUTH_USER_MODEL
),
(
'student'
,
'0002_auto_20151208_1034'
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'UserAttribute'
,
fields
=
[
(
'id'
,
models
.
AutoField
(
verbose_name
=
'ID'
,
serialize
=
False
,
auto_created
=
True
,
primary_key
=
True
)),
(
'created'
,
model_utils
.
fields
.
AutoCreatedField
(
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'created'
,
editable
=
False
)),
(
'modified'
,
model_utils
.
fields
.
AutoLastModifiedField
(
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'modified'
,
editable
=
False
)),
(
'name'
,
models
.
CharField
(
help_text
=
'Name of this user attribute.'
,
max_length
=
255
)),
(
'value'
,
models
.
CharField
(
help_text
=
'Value of this user attribute.'
,
max_length
=
255
)),
(
'user'
,
models
.
ForeignKey
(
related_name
=
'attributes'
,
to
=
settings
.
AUTH_USER_MODEL
)),
],
),
migrations
.
AlterUniqueTogether
(
name
=
'userattribute'
,
unique_together
=
set
([(
'user'
,
'name'
)]),
),
]
common/djangoapps/student/models.py
View file @
0e66baf4
...
...
@@ -40,6 +40,7 @@ from django.core.cache import cache
from
django_countries.fields
import
CountryField
import
dogstats_wrapper
as
dog_stats_api
from
eventtracking
import
tracker
from
model_utils.models
import
TimeStampedModel
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
simple_history.models
import
HistoricalRecords
...
...
@@ -2154,3 +2155,46 @@ class EnrollmentRefundConfiguration(ConfigurationModel):
def
refund_window
(
self
,
refund_window
):
"""Set the current refund window to the given timedelta."""
self
.
refund_window_microseconds
=
int
(
refund_window
.
total_seconds
()
*
1000000
)
class
UserAttribute
(
TimeStampedModel
):
"""
Record additional metadata about a user, stored as key/value pairs of text.
"""
class
Meta
(
object
):
# Ensure that at most one value exists for a given user/name.
unique_together
=
((
'user'
,
'name'
))
user
=
models
.
ForeignKey
(
User
,
related_name
=
'attributes'
)
name
=
models
.
CharField
(
max_length
=
255
,
help_text
=
_
(
"Name of this user attribute."
))
value
=
models
.
CharField
(
max_length
=
255
,
help_text
=
_
(
"Value of this user attribute."
))
def
__unicode__
(
self
):
"""Unicode representation of this attribute. """
return
u"[{username}] {name}: {value}"
.
format
(
name
=
self
.
name
,
value
=
self
.
value
,
username
=
self
.
user
.
username
,
)
@classmethod
def
set_user_attribute
(
cls
,
user
,
name
,
value
):
"""
Add an name/value pair as an attribute for the given
user. Overwrites any previous value for that name, if it
exists.
"""
cls
.
objects
.
filter
(
user
=
user
,
name
=
name
)
.
delete
()
cls
.
objects
.
create
(
user
=
user
,
name
=
name
,
value
=
value
)
@classmethod
def
get_user_attribute
(
cls
,
user
,
name
):
"""
Return the attribute value for the given user and name. If no such
value exists, returns None.
"""
try
:
return
cls
.
objects
.
get
(
user
=
user
,
name
=
name
)
.
value
except
cls
.
DoesNotExist
:
return
None
common/djangoapps/student/tests/test_create_account.py
View file @
0e66baf4
...
...
@@ -19,6 +19,7 @@ from notification_prefs import NOTIFICATION_PREF_KEY
from
edxmako.tests
import
mako_middleware_process_request
from
external_auth.models
import
ExternalAuthMap
import
student
from
student.models
import
UserAttribute
TEST_CS_URL
=
'https://comments.service.test:123/'
...
...
@@ -278,6 +279,24 @@ class TestCreateAccount(TestCase):
else
:
self
.
assertIsNone
(
preference
)
@unittest.skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
def
test_referral_attribution
(
self
):
"""
Verify that a referral attribution is recorded if an affiliate
cookie is present upon a new user's registration.
"""
affiliate_id
=
'test-partner'
self
.
client
.
cookies
[
settings
.
AFFILIATE_COOKIE_NAME
]
=
affiliate_id
user
=
self
.
create_account_and_fetch_profile
()
.
user
self
.
assertEqual
(
UserAttribute
.
get_user_attribute
(
user
,
settings
.
AFFILIATE_COOKIE_NAME
),
affiliate_id
)
@unittest.skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
def
test_no_referral
(
self
):
"""Verify that no referral is recorded when a cookie is not present."""
self
.
assertIsNone
(
self
.
client
.
cookies
.
get
(
settings
.
AFFILIATE_COOKIE_NAME
))
# pylint: disable=no-member
user
=
self
.
create_account_and_fetch_profile
()
.
user
self
.
assertIsNone
(
UserAttribute
.
get_user_attribute
(
user
,
settings
.
AFFILIATE_COOKIE_NAME
))
@ddt.ddt
class
TestCreateAccountValidation
(
TestCase
):
...
...
common/djangoapps/student/tests/tests.py
View file @
0e66baf4
...
...
@@ -24,7 +24,7 @@ from django.test.client import Client
from
course_modes.models
import
CourseMode
from
student.models
import
(
anonymous_id_for_user
,
user_by_anonymous_id
,
CourseEnrollment
,
unique_id_for_user
,
LinkedInAddToProfileConfiguration
unique_id_for_user
,
LinkedInAddToProfileConfiguration
,
UserAttribute
)
from
student.views
import
(
process_survey_link
,
...
...
@@ -1157,3 +1157,26 @@ class DashboardTestXSeriesPrograms(ModuleStoreTestCase, ProgramsApiConfigMixin):
self
.
assertContains
(
response
,
'This course is 1 of 3 courses in the'
,
count
)
self
.
assertContains
(
response
,
self
.
program_name
,
count
*
2
)
self
.
assertContains
(
response
,
'View XSeries Details'
,
count
)
class
UserAttributeTests
(
TestCase
):
"""Tests for the UserAttribute model."""
def
setUp
(
self
):
super
(
UserAttributeTests
,
self
)
.
setUp
()
self
.
user
=
UserFactory
()
self
.
name
=
'test'
self
.
value
=
'test-value'
def
test_get_set_attribute
(
self
):
self
.
assertIsNone
(
UserAttribute
.
get_user_attribute
(
self
.
user
,
self
.
name
))
UserAttribute
.
set_user_attribute
(
self
.
user
,
self
.
name
,
self
.
value
)
self
.
assertEqual
(
UserAttribute
.
get_user_attribute
(
self
.
user
,
self
.
name
),
self
.
value
)
new_value
=
'new_value'
UserAttribute
.
set_user_attribute
(
self
.
user
,
self
.
name
,
new_value
)
self
.
assertEqual
(
UserAttribute
.
get_user_attribute
(
self
.
user
,
self
.
name
),
new_value
)
def
test_unicode
(
self
):
UserAttribute
.
set_user_attribute
(
self
.
user
,
self
.
name
,
self
.
value
)
for
field
in
(
self
.
name
,
self
.
value
,
self
.
user
.
username
):
self
.
assertIn
(
field
,
unicode
(
UserAttribute
.
objects
.
get
(
user
=
self
.
user
)))
common/djangoapps/student/views.py
View file @
0e66baf4
...
...
@@ -111,7 +111,7 @@ from student.helpers import (
DISABLE_UNENROLL_CERT_STATES
,
)
from
student.cookies
import
set_logged_in_cookies
,
delete_logged_in_cookies
from
student.models
import
anonymous_id_for_user
from
student.models
import
anonymous_id_for_user
,
UserAttribute
from
shoppingcart.models
import
DonationConfiguration
,
CourseRegistrationCode
from
embargo
import
api
as
embargo_api
...
...
@@ -1815,6 +1815,8 @@ def create_account_with_params(request, params):
login
(
request
,
new_user
)
request
.
session
.
set_expiry
(
0
)
_record_registration_attribution
(
request
,
new_user
)
# TODO: there is no error checking here to see that the user actually logged in successfully,
# and is not yet an active user.
if
new_user
is
not
None
:
...
...
@@ -1855,6 +1857,16 @@ def _enroll_user_in_pending_courses(student):
)
def
_record_registration_attribution
(
request
,
user
):
"""
Attribute this user's registration to the referring affiliate, if
applicable.
"""
affiliate_id
=
request
.
COOKIES
.
get
(
settings
.
AFFILIATE_COOKIE_NAME
)
if
user
is
not
None
and
affiliate_id
is
not
None
:
UserAttribute
.
set_user_attribute
(
user
,
settings
.
AFFILIATE_COOKIE_NAME
,
affiliate_id
)
@csrf_exempt
def
create_account
(
request
,
post_override
=
None
):
"""
...
...
lms/envs/aws.py
View file @
0e66baf4
...
...
@@ -812,3 +812,5 @@ API_ACCESS_FROM_EMAIL = ENV_TOKENS.get('API_ACCESS_FROM_EMAIL')
# Mobile App Version Upgrade config
APP_UPGRADE_CACHE_TIMEOUT
=
ENV_TOKENS
.
get
(
'APP_UPGRADE_CACHE_TIMEOUT'
,
APP_UPGRADE_CACHE_TIMEOUT
)
AFFILIATE_COOKIE_NAME
=
ENV_TOKENS
.
get
(
'AFFILIATE_COOKIE_NAME'
,
AFFILIATE_COOKIE_NAME
)
lms/envs/common.py
View file @
0e66baf4
...
...
@@ -2900,3 +2900,6 @@ API_ACCESS_MANAGER_EMAIL = 'api-access@example.com'
API_ACCESS_FROM_EMAIL
=
'api-requests@example.com'
API_DOCUMENTATION_URL
=
'http://edx.readthedocs.org/projects/edx-platform-api/en/latest/overview.html'
AUTH_DOCUMENTATION_URL
=
'http://edx.readthedocs.org/projects/edx-platform-api/en/latest/authentication.html'
# Affiliate cookie tracking
AFFILIATE_COOKIE_NAME
=
'affiliate_id'
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment