Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
ecommerce
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
ecommerce
Commits
2e748dfd
Commit
2e748dfd
authored
Oct 14, 2015
by
Bill DeRusha
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #368 from edx/bderusha/boardman-traffic
Add IP to Segment tracking calls
parents
21856be7
d6a61002
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
66 additions
and
27 deletions
+66
-27
ecommerce/extensions/analytics/utils.py
+4
-3
ecommerce/extensions/checkout/signals.py
+2
-1
ecommerce/extensions/checkout/tests/test_mixins.py
+3
-1
ecommerce/extensions/fulfillment/modules.py
+9
-6
ecommerce/extensions/fulfillment/tests/test_modules.py
+39
-10
ecommerce/extensions/refund/signals.py
+2
-1
ecommerce/extensions/refund/tests/test_signals.py
+3
-1
ecommerce/notifications/notifications.py
+2
-2
ecommerce/tests/mixins.py
+2
-2
No files found.
ecommerce/extensions/analytics/utils.py
View file @
2e748dfd
...
...
@@ -13,13 +13,13 @@ def is_segment_configured():
def
parse_tracking_context
(
user
):
"""Extract user
and client ID
s from a user's tracking context.
"""Extract user
ID, client ID, and IP addres
s from a user's tracking context.
Arguments:
user (User): An instance of the User model.
Returns:
Tuple of strings
, user_tracking_id and lms_client_id
Tuple of strings
: user_tracking_id, lms_client_id, lms_ip
"""
tracking_context
=
user
.
tracking_context
or
{}
...
...
@@ -32,8 +32,9 @@ def parse_tracking_context(user):
user_tracking_id
=
'ecommerce-{}'
.
format
(
user
.
id
)
lms_client_id
=
tracking_context
.
get
(
'lms_client_id'
)
lms_ip
=
tracking_context
.
get
(
'lms_ip'
)
return
user_tracking_id
,
lms_client_id
return
user_tracking_id
,
lms_client_id
,
lms_ip
def
silence_exceptions
(
msg
):
...
...
ecommerce/extensions/checkout/signals.py
View file @
2e748dfd
...
...
@@ -26,7 +26,7 @@ def track_completed_order(sender, order=None, **kwargs): # pylint: disable=unus
if
not
(
is_segment_configured
()
and
order
.
total_excl_tax
>
0
):
return
user_tracking_id
,
lms_client_id
=
parse_tracking_context
(
order
.
user
)
user_tracking_id
,
lms_client_id
,
lms_ip
=
parse_tracking_context
(
order
.
user
)
analytics
.
track
(
user_tracking_id
,
...
...
@@ -51,6 +51,7 @@ def track_completed_order(sender, order=None, **kwargs): # pylint: disable=unus
],
},
context
=
{
'ip'
:
lms_ip
,
'Google Analytics'
:
{
'clientId'
:
lms_client_id
}
...
...
ecommerce/extensions/checkout/tests/test_mixins.py
View file @
2e748dfd
...
...
@@ -77,7 +77,7 @@ class EdxOrderPlacementMixinTests(BusinessIntelligenceMixin, RefundTestMixin, Te
Ensure that tracking events are fired with correct content when order
placement event handling is invoked.
"""
tracking_context
=
{
'lms_user_id'
:
'test-user-id'
,
'lms_client_id'
:
'test-client-id'
}
tracking_context
=
{
'lms_user_id'
:
'test-user-id'
,
'lms_client_id'
:
'test-client-id'
,
'lms_ip'
:
'127.0.0.1'
}
self
.
user
.
tracking_context
=
tracking_context
self
.
user
.
save
()
...
...
@@ -91,6 +91,7 @@ class EdxOrderPlacementMixinTests(BusinessIntelligenceMixin, RefundTestMixin, Te
self
.
order
,
tracking_context
[
'lms_user_id'
],
tracking_context
[
'lms_client_id'
],
tracking_context
[
'lms_ip'
],
self
.
order
.
number
,
self
.
order
.
currency
,
self
.
order
.
total_excl_tax
...
...
@@ -131,6 +132,7 @@ class EdxOrderPlacementMixinTests(BusinessIntelligenceMixin, RefundTestMixin, Te
self
.
order
,
'ecommerce-{}'
.
format
(
self
.
user
.
id
),
None
,
None
,
self
.
order
.
number
,
self
.
order
.
currency
,
self
.
order
.
total_excl_tax
...
...
ecommerce/extensions/fulfillment/modules.py
View file @
2e748dfd
...
...
@@ -93,17 +93,22 @@ class EnrollmentFulfillmentModule(BaseFulfillmentModule):
Allows the enrollment of a student via purchase of a 'seat'.
"""
def
_post_to_enrollment_api
(
self
,
data
,
client_id
=
None
):
def
_post_to_enrollment_api
(
self
,
data
,
user
):
enrollment_api_url
=
settings
.
ENROLLMENT_API_URL
timeout
=
settings
.
ENROLLMENT_FULFILLMENT_TIMEOUT
headers
=
{
'Content-Type'
:
'application/json'
,
'X-Edx-Api-Key'
:
settings
.
EDX_API_KEY
}
__
,
client_id
,
ip
=
parse_tracking_context
(
user
)
if
client_id
:
headers
[
'X-Edx-Ga-Client-Id'
]
=
client_id
if
ip
:
headers
[
'X-Forwarded-For'
]
=
ip
return
requests
.
post
(
enrollment_api_url
,
data
=
json
.
dumps
(
data
),
headers
=
headers
,
timeout
=
timeout
)
def
supports_line
(
self
,
line
):
...
...
@@ -186,8 +191,7 @@ class EnrollmentFulfillmentModule(BaseFulfillmentModule):
}
)
try
:
__
,
client_id
=
parse_tracking_context
(
order
.
user
)
response
=
self
.
_post_to_enrollment_api
(
data
,
client_id
=
client_id
)
response
=
self
.
_post_to_enrollment_api
(
data
,
user
=
order
.
user
)
if
response
.
status_code
==
status
.
HTTP_200_OK
:
line
.
set_status
(
LINE
.
COMPLETE
)
...
...
@@ -242,8 +246,7 @@ class EnrollmentFulfillmentModule(BaseFulfillmentModule):
},
}
__
,
client_id
=
parse_tracking_context
(
line
.
order
.
user
)
response
=
self
.
_post_to_enrollment_api
(
data
,
client_id
=
client_id
)
response
=
self
.
_post_to_enrollment_api
(
data
,
user
=
line
.
order
.
user
)
if
response
.
status_code
==
status
.
HTTP_200_OK
:
audit_log
(
...
...
ecommerce/extensions/fulfillment/tests/test_modules.py
View file @
2e748dfd
...
...
@@ -74,9 +74,11 @@ class EnrollmentFulfillmentModuleTests(CourseCatalogTestMixin, FulfillmentTestMi
self
.
assertEqual
(
1
,
len
(
supported_lines
))
@httpretty.activate
def
test_enrollment_module_fulfill
(
self
):
@mock.patch
(
'ecommerce.extensions.fulfillment.modules.parse_tracking_context'
)
def
test_enrollment_module_fulfill
(
self
,
parse_tracking_context
):
"""Happy path test to ensure we can properly fulfill enrollments."""
httpretty
.
register_uri
(
httpretty
.
POST
,
settings
.
ENROLLMENT_API_URL
,
status
=
200
,
body
=
'{}'
,
content_type
=
JSON
)
parse_tracking_context
.
return_value
=
(
'user_123'
,
'GA-123456789'
,
'11.22.33.44'
)
# Attempt to enroll.
with
LogCapture
(
LOGGER_NAME
)
as
l
:
EnrollmentFulfillmentModule
()
.
fulfill_product
(
self
.
order
,
list
(
self
.
order
.
lines
.
all
()))
...
...
@@ -101,8 +103,11 @@ class EnrollmentFulfillmentModuleTests(CourseCatalogTestMixin, FulfillmentTestMi
self
.
assertEqual
(
LINE
.
COMPLETE
,
line
.
status
)
actual
=
json
.
loads
(
httpretty
.
last_request
()
.
body
)
expected
=
{
last_request
=
httpretty
.
last_request
()
actual_body
=
json
.
loads
(
last_request
.
body
)
actual_headers
=
last_request
.
headers
expected_body
=
{
'user'
:
self
.
order
.
user
.
username
,
'is_active'
:
True
,
'mode'
:
self
.
certificate_type
,
...
...
@@ -111,7 +116,14 @@ class EnrollmentFulfillmentModuleTests(CourseCatalogTestMixin, FulfillmentTestMi
},
'enrollment_attributes'
:
[]
}
self
.
assertEqual
(
actual
,
expected
)
expected_headers
=
{
'X-Edx-Ga-Client-Id'
:
'GA-123456789'
,
'X-Forwarded-For'
:
'11.22.33.44'
,
}
self
.
assertDictContainsSubset
(
expected_headers
,
actual_headers
)
self
.
assertEqual
(
expected_body
,
actual_body
)
@override_settings
(
ENROLLMENT_API_URL
=
''
)
def
test_enrollment_module_not_configured
(
self
):
...
...
@@ -148,9 +160,11 @@ class EnrollmentFulfillmentModuleTests(CourseCatalogTestMixin, FulfillmentTestMi
self
.
assertEqual
(
LINE
.
FULFILLMENT_SERVER_ERROR
,
self
.
order
.
lines
.
all
()[
0
]
.
status
)
@httpretty.activate
def
test_revoke_product
(
self
):
@mock.patch
(
'ecommerce.extensions.fulfillment.modules.parse_tracking_context'
)
def
test_revoke_product
(
self
,
parse_tracking_context
):
""" The method should call the Enrollment API to un-enroll the student, and return True. """
httpretty
.
register_uri
(
httpretty
.
POST
,
settings
.
ENROLLMENT_API_URL
,
status
=
200
,
body
=
'{}'
,
content_type
=
JSON
)
parse_tracking_context
.
return_value
=
(
'user_123'
,
'GA-123456789'
,
'11.22.33.44'
)
line
=
self
.
order
.
lines
.
first
()
with
LogCapture
(
LOGGER_NAME
)
as
l
:
...
...
@@ -172,8 +186,11 @@ class EnrollmentFulfillmentModuleTests(CourseCatalogTestMixin, FulfillmentTestMi
)
)
actual
=
json
.
loads
(
httpretty
.
last_request
()
.
body
)
expected
=
{
last_request
=
httpretty
.
last_request
()
actual_body
=
json
.
loads
(
last_request
.
body
)
actual_headers
=
last_request
.
headers
expected_body
=
{
'user'
:
self
.
order
.
user
.
username
,
'is_active'
:
False
,
'mode'
:
self
.
certificate_type
,
...
...
@@ -181,7 +198,14 @@ class EnrollmentFulfillmentModuleTests(CourseCatalogTestMixin, FulfillmentTestMi
'course_id'
:
self
.
course_id
,
},
}
self
.
assertEqual
(
actual
,
expected
)
expected_headers
=
{
'X-Edx-Ga-Client-Id'
:
'GA-123456789'
,
'X-Forwarded-For'
:
'11.22.33.44'
,
}
self
.
assertDictContainsSubset
(
expected_headers
,
actual_headers
)
self
.
assertEqual
(
expected_body
,
actual_body
)
@httpretty.activate
def
test_revoke_product_expected_error
(
self
):
...
...
@@ -302,6 +326,10 @@ class EnrollmentFulfillmentModuleTests(CourseCatalogTestMixin, FulfillmentTestMi
'enrollment_attributes'
:
[]
}
# Create a dummy user and attach the tracking_context
user
=
UserFactory
()
user
.
tracking_context
=
{
'lms_user_id'
:
'1'
,
'lms_client_id'
:
'123.123'
,
'lms_ip'
:
'11.22.33.44'
}
# Now call the enrollment api to send POST request to LMS and verify
# that the header of the request being sent contains the analytics
# header 'x-edx-ga-client-id'.
...
...
@@ -309,8 +337,9 @@ class EnrollmentFulfillmentModuleTests(CourseCatalogTestMixin, FulfillmentTestMi
# not available for ecommerce tests.
try
:
# pylint: disable=protected-access
EnrollmentFulfillmentModule
()
.
_post_to_enrollment_api
(
data
=
data
,
client_id
=
'123.123'
)
EnrollmentFulfillmentModule
()
.
_post_to_enrollment_api
(
data
=
data
,
user
=
user
)
except
ConnectionError
as
exp
:
# Check that the enrollment request object has the analytics header
# 'x-edx-ga-client-id'.
# 'x-edx-ga-client-id'
and 'x-forwarded-for'
.
self
.
assertEqual
(
exp
.
request
.
headers
.
get
(
'x-edx-ga-client-id'
),
'123.123'
)
self
.
assertEqual
(
exp
.
request
.
headers
.
get
(
'x-forwarded-for'
),
'11.22.33.44'
)
ecommerce/extensions/refund/signals.py
View file @
2e748dfd
...
...
@@ -16,7 +16,7 @@ def track_completed_refund(sender, refund=None, **kwargs): # pylint: disable=un
if
not
(
is_segment_configured
()
and
refund
.
total_credit_excl_tax
>
0
):
return
user_tracking_id
,
lms_client_id
=
parse_tracking_context
(
refund
.
user
)
user_tracking_id
,
lms_client_id
,
lms_ip
=
parse_tracking_context
(
refund
.
user
)
# Ecommerce transaction reversal, performed by emitting an event which is the inverse of an
# order completion event emitted previously.
...
...
@@ -44,6 +44,7 @@ def track_completed_refund(sender, refund=None, **kwargs): # pylint: disable=un
],
},
context
=
{
'ip'
:
lms_ip
,
'Google Analytics'
:
{
'clientId'
:
lms_client_id
}
...
...
ecommerce/extensions/refund/tests/test_signals.py
View file @
2e748dfd
...
...
@@ -21,7 +21,7 @@ class RefundTrackingTests(BusinessIntelligenceMixin, RefundTestMixin, TestCase):
def
test_successful_refund_tracking
(
self
,
mock_track
):
"""Verify that a successfully placed refund is tracked when Segment is enabled."""
tracking_context
=
{
'lms_user_id'
:
'test-user-id'
,
'lms_client_id'
:
'test-client-id'
}
tracking_context
=
{
'lms_user_id'
:
'test-user-id'
,
'lms_client_id'
:
'test-client-id'
,
'lms_ip'
:
'127.0.0.1'
}
self
.
refund
.
user
.
tracking_context
=
tracking_context
self
.
refund
.
user
.
save
()
...
...
@@ -37,6 +37,7 @@ class RefundTrackingTests(BusinessIntelligenceMixin, RefundTestMixin, TestCase):
self
.
refund
,
tracking_context
[
'lms_user_id'
],
tracking_context
[
'lms_client_id'
],
tracking_context
[
'lms_ip'
],
self
.
order
.
number
,
self
.
refund
.
currency
,
self
.
refund
.
total_credit_excl_tax
...
...
@@ -68,6 +69,7 @@ class RefundTrackingTests(BusinessIntelligenceMixin, RefundTestMixin, TestCase):
self
.
refund
,
'ecommerce-{}'
.
format
(
self
.
user
.
id
),
None
,
None
,
self
.
order
.
number
,
self
.
refund
.
currency
,
self
.
refund
.
total_credit_excl_tax
...
...
ecommerce/notifications/notifications.py
View file @
2e748dfd
...
...
@@ -22,10 +22,10 @@ def send_notification(user, commtype_code, context):
"""
tracking_id
,
client_id
=
parse_tracking_context
(
user
)
tracking_id
,
client_id
,
ip
=
parse_tracking_context
(
user
)
tracking_pixel
=
'https://www.google-analytics.com/collect?v=1&t=event&ec=email&ea=open&tid={tracking_id}'
\
'&cid={client_id}
'
.
format
(
tracking_id
=
tracking_id
,
client_id
=
client_id
)
'&cid={client_id}
&uip={ip}'
.
format
(
tracking_id
=
tracking_id
,
client_id
=
client_id
,
ip
=
ip
)
full_name
=
user
.
get_full_name
()
context
.
update
({
'full_name'
:
full_name
,
...
...
ecommerce/tests/mixins.py
View file @
2e748dfd
...
...
@@ -171,13 +171,13 @@ class BusinessIntelligenceMixin(object):
"""Provides assertions for test cases validating the emission of business intelligence events."""
def
assert_correct_event
(
self
,
mock_track
,
instance
,
expected_user_id
,
expected_client_id
,
order_number
,
currency
,
total
self
,
mock_track
,
instance
,
expected_user_id
,
expected_client_id
,
expected_ip
,
order_number
,
currency
,
total
):
"""Check that the tracking context was correctly reflected in the emitted event."""
(
event_user_id
,
event_name
,
event_payload
),
kwargs
=
mock_track
.
call_args
self
.
assertEqual
(
event_user_id
,
expected_user_id
)
self
.
assertEqual
(
event_name
,
'Completed Order'
)
self
.
assertEqual
(
kwargs
[
'context'
],
{
'Google Analytics'
:
{
'clientId'
:
expected_client_id
}})
self
.
assertEqual
(
kwargs
[
'context'
],
{
'
ip'
:
expected_ip
,
'
Google Analytics'
:
{
'clientId'
:
expected_client_id
}})
self
.
assert_correct_event_payload
(
instance
,
event_payload
,
order_number
,
currency
,
total
)
def
assert_correct_event_payload
(
self
,
instance
,
event_payload
,
order_number
,
currency
,
total
):
...
...
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