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
a6873cb8
Commit
a6873cb8
authored
Sep 29, 2015
by
Bill DeRusha
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #9875 from edx/bderusha/segment-cleanup
Segment Clean Up
parents
14e1ef13
c721ff5a
Show whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
73 additions
and
97 deletions
+73
-97
cms/envs/aws.py
+2
-5
cms/envs/bok_choy.env.json
+0
-1
cms/envs/common.py
+2
-2
cms/envs/dev.py
+2
-4
cms/envs/test.py
+2
-2
cms/envs/yaml_config.py
+1
-4
cms/templates/widgets/segment-io.html
+6
-6
common/djangoapps/student/models.py
+1
-1
common/djangoapps/student/views.py
+3
-3
common/djangoapps/third_party_auth/pipeline.py
+2
-2
common/djangoapps/track/shim.py
+1
-1
common/djangoapps/track/views/segmentio.py
+15
-15
common/djangoapps/track/views/tests/test_segmentio.py
+6
-6
lms/djangoapps/courseware/tests/test_views.py
+2
-2
lms/djangoapps/courseware/views.py
+1
-1
lms/djangoapps/shoppingcart/models.py
+1
-1
lms/djangoapps/shoppingcart/tests/test_models.py
+3
-6
lms/djangoapps/verify_student/tests/test_views.py
+4
-4
lms/djangoapps/verify_student/views.py
+2
-2
lms/envs/aws.py
+1
-4
lms/envs/bok_choy.env.json
+0
-1
lms/envs/common.py
+1
-3
lms/envs/dev.py
+3
-5
lms/envs/yaml_config.py
+0
-3
lms/startup.py
+3
-4
lms/templates/widgets/segment-io.html
+7
-7
openedx/core/djangoapps/user_api/preferences/api.py
+1
-1
requirements/edx/base.txt
+1
-1
No files found.
cms/envs/aws.py
View file @
a6873cb8
...
@@ -243,11 +243,8 @@ if 'DJFS' in AUTH_TOKENS and AUTH_TOKENS['DJFS'] is not None:
...
@@ -243,11 +243,8 @@ if 'DJFS' in AUTH_TOKENS and AUTH_TOKENS['DJFS'] is not None:
EMAIL_HOST_USER
=
AUTH_TOKENS
.
get
(
'EMAIL_HOST_USER'
,
EMAIL_HOST_USER
)
EMAIL_HOST_USER
=
AUTH_TOKENS
.
get
(
'EMAIL_HOST_USER'
,
EMAIL_HOST_USER
)
EMAIL_HOST_PASSWORD
=
AUTH_TOKENS
.
get
(
'EMAIL_HOST_PASSWORD'
,
EMAIL_HOST_PASSWORD
)
EMAIL_HOST_PASSWORD
=
AUTH_TOKENS
.
get
(
'EMAIL_HOST_PASSWORD'
,
EMAIL_HOST_PASSWORD
)
# If Segment.io key specified, load it and turn on Segment.io if the feature flag is set
# Note that this is the Studio key for Segment. There is a separate key for the LMS.
# Note that this is the Studio key. There is a separate key for the LMS.
SEGMENT_KEY
=
AUTH_TOKENS
.
get
(
'SEGMENT_KEY'
)
SEGMENT_IO_KEY
=
AUTH_TOKENS
.
get
(
'SEGMENT_IO_KEY'
)
if
SEGMENT_IO_KEY
:
FEATURES
[
'SEGMENT_IO'
]
=
ENV_TOKENS
.
get
(
'SEGMENT_IO'
,
False
)
AWS_ACCESS_KEY_ID
=
AUTH_TOKENS
[
"AWS_ACCESS_KEY_ID"
]
AWS_ACCESS_KEY_ID
=
AUTH_TOKENS
[
"AWS_ACCESS_KEY_ID"
]
if
AWS_ACCESS_KEY_ID
==
""
:
if
AWS_ACCESS_KEY_ID
==
""
:
...
...
cms/envs/bok_choy.env.json
View file @
a6873cb8
...
@@ -94,7 +94,6 @@
...
@@ -94,7 +94,6 @@
"MEDIA_URL"
:
""
,
"MEDIA_URL"
:
""
,
"MKTG_URL_LINK_MAP"
:
{},
"MKTG_URL_LINK_MAP"
:
{},
"PLATFORM_NAME"
:
"edX"
,
"PLATFORM_NAME"
:
"edX"
,
"SEGMENT_IO_LMS"
:
true
,
"SERVER_EMAIL"
:
"devops@example.com"
,
"SERVER_EMAIL"
:
"devops@example.com"
,
"SESSION_COOKIE_DOMAIN"
:
null
,
"SESSION_COOKIE_DOMAIN"
:
null
,
"SITE_NAME"
:
"localhost"
,
"SITE_NAME"
:
"localhost"
,
...
...
cms/envs/common.py
View file @
a6873cb8
...
@@ -77,8 +77,8 @@ FEATURES = {
...
@@ -77,8 +77,8 @@ FEATURES = {
# email address for studio staff (eg to request course creation)
# email address for studio staff (eg to request course creation)
'STUDIO_REQUEST_EMAIL'
:
''
,
'STUDIO_REQUEST_EMAIL'
:
''
,
# Segment
.io
- must explicitly turn it on for production
# Segment - must explicitly turn it on for production
'SEGMENT_
IO'
:
Fals
e
,
'SEGMENT_
KEY'
:
Non
e
,
# Enable URL that shows information about the status of various services
# Enable URL that shows information about the status of various services
'ENABLE_SERVICE_STATUS'
:
False
,
'ENABLE_SERVICE_STATUS'
:
False
,
...
...
cms/envs/dev.py
View file @
a6873cb8
...
@@ -164,12 +164,10 @@ FEATURES['ENABLE_SERVICE_STATUS'] = True
...
@@ -164,12 +164,10 @@ FEATURES['ENABLE_SERVICE_STATUS'] = True
############################# SEGMENT-IO ##################################
############################# SEGMENT-IO ##################################
# If there's an environment variable set, grab it
and turn on Segment.io
# If there's an environment variable set, grab it
to turn on Segment
# Note that this is the Studio key. There is a separate key for the LMS.
# Note that this is the Studio key. There is a separate key for the LMS.
import
os
import
os
SEGMENT_IO_KEY
=
os
.
environ
.
get
(
'SEGMENT_IO_KEY'
)
SEGMENT_KEY
=
os
.
environ
.
get
(
'SEGMENT_KEY'
)
if
SEGMENT_IO_KEY
:
FEATURES
[
'SEGMENT_IO'
]
=
True
#####################################################################
#####################################################################
...
...
cms/envs/test.py
View file @
a6873cb8
...
@@ -210,8 +210,8 @@ PASSWORD_HASHERS = (
...
@@ -210,8 +210,8 @@ PASSWORD_HASHERS = (
'django.contrib.auth.hashers.MD5PasswordHasher'
,
'django.contrib.auth.hashers.MD5PasswordHasher'
,
)
)
#
dummy segment-io
key
#
No segment
key
SEGMENT_
IO_KEY
=
'***REMOVED***'
SEGMENT_
KEY
=
None
FEATURES
[
'ENABLE_SERVICE_STATUS'
]
=
True
FEATURES
[
'ENABLE_SERVICE_STATUS'
]
=
True
...
...
cms/envs/yaml_config.py
View file @
a6873cb8
...
@@ -120,7 +120,7 @@ ADDL_INSTALLED_APPS = []
...
@@ -120,7 +120,7 @@ ADDL_INSTALLED_APPS = []
AUTH_USE_CAS
=
False
AUTH_USE_CAS
=
False
CAS_ATTRIBUTE_CALLBACK
=
None
CAS_ATTRIBUTE_CALLBACK
=
None
MICROSITE_ROOT_DIR
=
''
MICROSITE_ROOT_DIR
=
''
SEGMENT_
IO
=
Fals
e
SEGMENT_
KEY
=
Non
e
DATADOG
=
{}
DATADOG
=
{}
ADDL_INSTALLED_APPS
=
[]
ADDL_INSTALLED_APPS
=
[]
LOCAL_LOGLEVEL
=
'INFO'
LOCAL_LOGLEVEL
=
'INFO'
...
@@ -235,9 +235,6 @@ vars().update(AUTH_TOKENS)
...
@@ -235,9 +235,6 @@ vars().update(AUTH_TOKENS)
# Manipulate imported settings with code
# Manipulate imported settings with code
#
#
if
SEGMENT_IO_KEY
:
FEATURES
[
'SEGMENT_IO'
]
=
SEGMENT_IO
if
AWS_ACCESS_KEY_ID
==
""
:
if
AWS_ACCESS_KEY_ID
==
""
:
AWS_ACCESS_KEY_ID
=
None
AWS_ACCESS_KEY_ID
=
None
...
...
cms/templates/widgets/segment-io.html
View file @
a6873cb8
...
@@ -6,8 +6,8 @@
...
@@ -6,8 +6,8 @@
%
>
%
>
% endif
% endif
% if settings.
FEATURES.get('SEGMENT_IO')
:
% if settings.
SEGMENT_KEY
:
<!-- begin Segment
.io
-->
<!-- begin Segment -->
<script
type=
"text/javascript"
>
<script
type=
"text/javascript"
>
// if inside course, inject the course location into the JS namespace
// if inside course, inject the course location into the JS namespace
%
if
context_course
:
%
if
context_course
:
...
@@ -15,7 +15,7 @@
...
@@ -15,7 +15,7 @@
%
endif
%
endif
var
analytics
=
analytics
||
[];
analytics
.
load
=
function
(
e
){
var
t
=
document
.
createElement
(
"script"
);
t
.
type
=
"text/javascript"
,
t
.
async
=!
0
,
t
.
src
=
(
"https:"
===
document
.
location
.
protocol
?
"https://"
:
"http://"
)
+
"d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/"
+
e
+
"/analytics.min.js"
;
var
n
=
document
.
getElementsByTagName
(
"script"
)[
0
];
n
.
parentNode
.
insertBefore
(
t
,
n
);
var
r
=
function
(
e
){
return
function
(){
analytics
.
push
([
e
].
concat
(
Array
.
prototype
.
slice
.
call
(
arguments
,
0
)))}},
i
=
[
"identify"
,
"track"
,
"trackLink"
,
"trackForm"
,
"trackClick"
,
"trackSubmit"
,
"pageview"
,
"ab"
,
"alias"
,
"ready"
];
for
(
var
s
=
0
;
s
<
i
.
length
;
s
++
)
analytics
[
i
[
s
]]
=
r
(
i
[
s
])};
var
analytics
=
analytics
||
[];
analytics
.
load
=
function
(
e
){
var
t
=
document
.
createElement
(
"script"
);
t
.
type
=
"text/javascript"
,
t
.
async
=!
0
,
t
.
src
=
(
"https:"
===
document
.
location
.
protocol
?
"https://"
:
"http://"
)
+
"d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/"
+
e
+
"/analytics.min.js"
;
var
n
=
document
.
getElementsByTagName
(
"script"
)[
0
];
n
.
parentNode
.
insertBefore
(
t
,
n
);
var
r
=
function
(
e
){
return
function
(){
analytics
.
push
([
e
].
concat
(
Array
.
prototype
.
slice
.
call
(
arguments
,
0
)))}},
i
=
[
"identify"
,
"track"
,
"trackLink"
,
"trackForm"
,
"trackClick"
,
"trackSubmit"
,
"pageview"
,
"ab"
,
"alias"
,
"ready"
];
for
(
var
s
=
0
;
s
<
i
.
length
;
s
++
)
analytics
[
i
[
s
]]
=
r
(
i
[
s
])};
analytics
.
load
(
"${ settings.SEGMENT_
IO_
KEY }"
);
analytics
.
load
(
"${ settings.SEGMENT_KEY }"
);
%
if
user
.
is_authenticated
():
%
if
user
.
is_authenticated
():
analytics
.
identify
(
"${ user.id }"
,
{
analytics
.
identify
(
"${ user.id }"
,
{
...
@@ -25,9 +25,9 @@
...
@@ -25,9 +25,9 @@
%
endif
%
endif
</script>
</script>
<!-- end Segment
.io
-->
<!-- end Segment -->
% else:
% else:
<!-- dummy
segment.io
-->
<!-- dummy
Segment
-->
<script
type=
"text/javascript"
>
<script
type=
"text/javascript"
>
%
if
context_course
:
%
if
context_course
:
var
course_location_analytics
=
"${locator | escapejs}"
;
var
course_location_analytics
=
"${locator | escapejs}"
;
...
@@ -36,5 +36,5 @@
...
@@ -36,5 +36,5 @@
"track"
:
function
()
{}
"track"
:
function
()
{}
};
};
</script>
</script>
<!-- end dummy
segment.io
-->
<!-- end dummy
Segment
-->
% endif
% endif
common/djangoapps/student/models.py
View file @
a6873cb8
...
@@ -1052,7 +1052,7 @@ class CourseEnrollment(models.Model):
...
@@ -1052,7 +1052,7 @@ class CourseEnrollment(models.Model):
with
tracker
.
get_tracker
()
.
context
(
event_name
,
context
):
with
tracker
.
get_tracker
()
.
context
(
event_name
,
context
):
tracker
.
emit
(
event_name
,
data
)
tracker
.
emit
(
event_name
,
data
)
if
settings
.
FEATURES
.
get
(
'SEGMENT_IO_LMS'
)
and
settings
.
SEGMENT_IO_LMS
_KEY
:
if
settings
.
SEGMENT
_KEY
:
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
analytics
.
track
(
self
.
user_id
,
event_name
,
{
analytics
.
track
(
self
.
user_id
,
event_name
,
{
'category'
:
'conversion'
,
'category'
:
'conversion'
,
...
...
common/djangoapps/student/views.py
View file @
a6873cb8
...
@@ -1163,11 +1163,11 @@ def login_user(request, error=""): # pylint: disable=too-many-statements,unused
...
@@ -1163,11 +1163,11 @@ def login_user(request, error=""): # pylint: disable=too-many-statements,unused
LoginFailures
.
clear_lockout_counter
(
user
)
LoginFailures
.
clear_lockout_counter
(
user
)
# Track the user's sign in
# Track the user's sign in
if
settings
.
FEATURES
.
get
(
'SEGMENT_IO_LMS'
)
and
hasattr
(
settings
,
'SEGMENT_IO_LMS_KEY'
)
:
if
settings
.
SEGMENT_KEY
:
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
analytics
.
identify
(
user
.
id
,
{
analytics
.
identify
(
user
.
id
,
{
'email'
:
email
,
'email'
:
email
,
'username'
:
username
,
'username'
:
username
})
})
analytics
.
track
(
analytics
.
track
(
...
@@ -1601,7 +1601,7 @@ def create_account_with_params(request, params):
...
@@ -1601,7 +1601,7 @@ def create_account_with_params(request, params):
third_party_provider
=
provider
.
Registry
.
get_from_pipeline
(
running_pipeline
)
third_party_provider
=
provider
.
Registry
.
get_from_pipeline
(
running_pipeline
)
# Track the user's registration
# Track the user's registration
if
settings
.
FEATURES
.
get
(
'SEGMENT_IO_LMS'
)
and
hasattr
(
settings
,
'SEGMENT_IO_LMS_KEY'
)
:
if
settings
.
SEGMENT_KEY
:
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
identity_args
=
[
identity_args
=
[
user
.
id
,
# pylint: disable=no-member
user
.
id
,
# pylint: disable=no-member
...
...
common/djangoapps/third_party_auth/pipeline.py
View file @
a6873cb8
...
@@ -585,7 +585,7 @@ def set_logged_in_cookies(backend=None, user=None, strategy=None, auth_entry=Non
...
@@ -585,7 +585,7 @@ def set_logged_in_cookies(backend=None, user=None, strategy=None, auth_entry=Non
@partial.partial
@partial.partial
def
login_analytics
(
strategy
,
auth_entry
,
*
args
,
**
kwargs
):
def
login_analytics
(
strategy
,
auth_entry
,
*
args
,
**
kwargs
):
""" Sends login info to Segment
.io
"""
""" Sends login info to Segment """
event_name
=
None
event_name
=
None
if
auth_entry
==
AUTH_ENTRY_LOGIN
:
if
auth_entry
==
AUTH_ENTRY_LOGIN
:
...
@@ -593,7 +593,7 @@ def login_analytics(strategy, auth_entry, *args, **kwargs):
...
@@ -593,7 +593,7 @@ def login_analytics(strategy, auth_entry, *args, **kwargs):
elif
auth_entry
in
[
AUTH_ENTRY_ACCOUNT_SETTINGS
]:
elif
auth_entry
in
[
AUTH_ENTRY_ACCOUNT_SETTINGS
]:
event_name
=
'edx.bi.user.account.linked'
event_name
=
'edx.bi.user.account.linked'
if
event_name
is
not
None
and
hasattr
(
settings
,
'SEGMENT_IO_LMS_KEY'
)
and
settings
.
SEGMENT_IO_LMS
_KEY
:
if
event_name
is
not
None
and
settings
.
SEGMENT
_KEY
:
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
analytics
.
track
(
analytics
.
track
(
kwargs
[
'user'
]
.
id
,
kwargs
[
'user'
]
.
id
,
...
...
common/djangoapps/track/shim.py
View file @
a6873cb8
...
@@ -67,7 +67,7 @@ def remove_shim_context(event):
...
@@ -67,7 +67,7 @@ def remove_shim_context(event):
context
=
event
[
'context'
]
context
=
event
[
'context'
]
# These fields are present elsewhere in the event at this point
# These fields are present elsewhere in the event at this point
context_fields_to_remove
=
set
(
CONTEXT_FIELDS_TO_INCLUDE
)
context_fields_to_remove
=
set
(
CONTEXT_FIELDS_TO_INCLUDE
)
# This field is only used for Segment
.io
web analytics and does not concern researchers
# This field is only used for Segment web analytics and does not concern researchers
context_fields_to_remove
.
add
(
'client_id'
)
context_fields_to_remove
.
add
(
'client_id'
)
for
field
in
context_fields_to_remove
:
for
field
in
context_fields_to_remove
:
if
field
in
context
:
if
field
in
context
:
...
...
common/djangoapps/track/views/segmentio.py
View file @
a6873cb8
"""Handle events that were forwarded from the
segment.io
webhook integration"""
"""Handle events that were forwarded from the
Segment
webhook integration"""
import
datetime
import
datetime
import
json
import
json
...
@@ -35,28 +35,28 @@ ERROR_MISSING_RECEIVED_AT = 'Required receivedAt field not found'
...
@@ -35,28 +35,28 @@ ERROR_MISSING_RECEIVED_AT = 'Required receivedAt field not found'
@csrf_exempt
@csrf_exempt
def
segmentio_event
(
request
):
def
segmentio_event
(
request
):
"""
"""
An endpoint for logging events using
segment.io
's webhook integration.
An endpoint for logging events using
Segment
's webhook integration.
segment.io
provides a custom integration mechanism that initiates a request to a configurable URL every time an
Segment
provides a custom integration mechanism that initiates a request to a configurable URL every time an
event is received by their system. This endpoint is designed to receive those requests and convert the events into
event is received by their system. This endpoint is designed to receive those requests and convert the events into
standard tracking log entries.
standard tracking log entries.
For now we limit the scope of handled events to track and screen events from mobile devices. In the future we could
For now we limit the scope of handled events to track and screen events from mobile devices. In the future we could
enable logging of other types of events, however, there is significant overlap with our non-
segment.io
based event
enable logging of other types of events, however, there is significant overlap with our non-
Segment
based event
tracking. Given that
segment.io
is closed third party solution we are limiting its required usage to just
tracking. Given that
Segment
is closed third party solution we are limiting its required usage to just
collecting events from mobile devices for the time being.
collecting events from mobile devices for the time being.
Many of the root fields of a standard edX tracking event are read out of the "properties" dictionary provided by the
Many of the root fields of a standard edX tracking event are read out of the "properties" dictionary provided by the
segment.io
event, which is, in turn, provided by the client that emitted the event.
Segment
event, which is, in turn, provided by the client that emitted the event.
In order for an event to be accepted and logged the "key" query string parameter must exactly match the django
In order for an event to be accepted and logged the "key" query string parameter must exactly match the django
setting TRACKING_SEGMENTIO_WEBHOOK_SECRET. While the endpoint is public, we want to limit access to it to the
setting TRACKING_SEGMENTIO_WEBHOOK_SECRET. While the endpoint is public, we want to limit access to it to the
segment.io
servers only.
Segment
servers only.
"""
"""
# Validate the security token. We must use a query string parameter for this since we cannot customize the POST body
# Validate the security token. We must use a query string parameter for this since we cannot customize the POST body
# in the
segment.io
webhook configuration, we can only change the URL that they call, so we force this token to be
# in the
Segment
webhook configuration, we can only change the URL that they call, so we force this token to be
# included in the URL and reject any requests that do not include it. This also assumes HTTPS is used to make the
# included in the URL and reject any requests that do not include it. This also assumes HTTPS is used to make the
# connection between their server and ours.
# connection between their server and ours.
expected_secret
=
getattr
(
settings
,
'TRACKING_SEGMENTIO_WEBHOOK_SECRET'
,
None
)
expected_secret
=
getattr
(
settings
,
'TRACKING_SEGMENTIO_WEBHOOK_SECRET'
,
None
)
...
@@ -68,7 +68,7 @@ def segmentio_event(request):
...
@@ -68,7 +68,7 @@ def segmentio_event(request):
track_segmentio_event
(
request
)
track_segmentio_event
(
request
)
except
EventValidationError
as
err
:
except
EventValidationError
as
err
:
log
.
warning
(
log
.
warning
(
'Unable to process event received from
segment.io
: message="
%
s" event="
%
s"'
,
'Unable to process event received from
Segment
: message="
%
s" event="
%
s"'
,
str
(
err
),
str
(
err
),
request
.
body
request
.
body
)
)
...
@@ -85,24 +85,24 @@ class EventValidationError(Exception):
...
@@ -85,24 +85,24 @@ class EventValidationError(Exception):
def
track_segmentio_event
(
request
):
# pylint: disable=too-many-statements
def
track_segmentio_event
(
request
):
# pylint: disable=too-many-statements
"""
"""
Record an event received from
segment.io
to the tracking logs.
Record an event received from
Segment
to the tracking logs.
This method assumes that the event has come from a trusted source.
This method assumes that the event has come from a trusted source.
The received event must meet the following conditions in order to be logged:
The received event must meet the following conditions in order to be logged:
* The value of the "type" field of the event must be included in the list specified by the django setting
* The value of the "type" field of the event must be included in the list specified by the django setting
TRACKING_SEGMENTIO_ALLOWED_TYPES. In order to make use of *all* of the features
segment.io
offers we would have
TRACKING_SEGMENTIO_ALLOWED_TYPES. In order to make use of *all* of the features
Segment
offers we would have
to implement some sort of persistent storage of information contained in some actions (like identify). For now,
to implement some sort of persistent storage of information contained in some actions (like identify). For now,
we defer support of those actions and just support a limited set that can be handled without storing information
we defer support of those actions and just support a limited set that can be handled without storing information
in external state.
in external state.
* The value of the standard "userId" field of the event must be an integer that can be used to look up the user
* The value of the standard "userId" field of the event must be an integer that can be used to look up the user
using the primary key of the User model.
using the primary key of the User model.
* Include a "name" field in the properties dictionary that indicates the edX event name. Note this can differ
* Include a "name" field in the properties dictionary that indicates the edX event name. Note this can differ
from the "event" field found in the root of a
segment.io
event. The "event" field at the root of the structure is
from the "event" field found in the root of a
Segment
event. The "event" field at the root of the structure is
intended to be human readable, the "name" field is expected to conform to the standard for naming events
intended to be human readable, the "name" field is expected to conform to the standard for naming events
found in the edX data documentation.
found in the edX data documentation.
* Have originated from a known and trusted
segment.io
client library. The django setting
* Have originated from a known and trusted
Segment
client library. The django setting
TRACKING_SEGMENTIO_SOURCE_MAP maps the known library names to internal "event_source" strings. In order to be
TRACKING_SEGMENTIO_SOURCE_MAP maps the known library names to internal "event_source" strings. In order to be
logged the event must have a library name that is a valid key in that map.
logged the event must have a library name that is a valid key in that map.
...
@@ -122,11 +122,11 @@ def track_segmentio_event(request): # pylint: disable=too-many-statements
...
@@ -122,11 +122,11 @@ def track_segmentio_event(request): # pylint: disable=too-many-statements
# We mostly care about the properties
# We mostly care about the properties
segment_properties
=
full_segment_event
.
get
(
'properties'
,
{})
segment_properties
=
full_segment_event
.
get
(
'properties'
,
{})
# Start with the context provided by
segment.io
in the "client" field if it exists
# Start with the context provided by
Segment
in the "client" field if it exists
# We should tightly control which fields actually get included in the event emitted.
# We should tightly control which fields actually get included in the event emitted.
segment_context
=
full_segment_event
.
get
(
'context'
)
segment_context
=
full_segment_event
.
get
(
'context'
)
# Build up the event context by parsing fields out of the event received from
segment.io
# Build up the event context by parsing fields out of the event received from
Segment
context
=
{}
context
=
{}
library_name
=
segment_context
.
get
(
'library'
,
{})
.
get
(
'name'
)
library_name
=
segment_context
.
get
(
'library'
,
{})
.
get
(
'name'
)
...
...
common/djangoapps/track/views/tests/test_segmentio.py
View file @
a6873cb8
"""Ensure we can parse events sent to us from the
segment.io
webhook integration"""
"""Ensure we can parse events sent to us from the
Segment
webhook integration"""
from
datetime
import
datetime
from
datetime
import
datetime
import
json
import
json
...
@@ -50,7 +50,7 @@ def expect_failure_with_message(message):
...
@@ -50,7 +50,7 @@ def expect_failure_with_message(message):
EVENT_TRACKING_PROCESSORS
=
MOBILE_SHIM_PROCESSOR
,
EVENT_TRACKING_PROCESSORS
=
MOBILE_SHIM_PROCESSOR
,
)
)
class
SegmentIOTrackingTestCase
(
EventTrackingTestCase
):
class
SegmentIOTrackingTestCase
(
EventTrackingTestCase
):
"""Test processing of
segment.io
events"""
"""Test processing of
Segment
events"""
def
setUp
(
self
):
def
setUp
(
self
):
super
(
SegmentIOTrackingTestCase
,
self
)
.
setUp
()
super
(
SegmentIOTrackingTestCase
,
self
)
.
setUp
()
...
@@ -85,7 +85,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
...
@@ -85,7 +85,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
self
.
assert_no_events_emitted
()
self
.
assert_no_events_emitted
()
def
create_request
(
self
,
key
=
None
,
**
kwargs
):
def
create_request
(
self
,
key
=
None
,
**
kwargs
):
"""Create a fake request that emulates a request from the
segment.io
servers to ours"""
"""Create a fake request that emulates a request from the
Segment
servers to ours"""
if
key
is
None
:
if
key
is
None
:
key
=
SECRET
key
=
SECRET
...
@@ -106,7 +106,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
...
@@ -106,7 +106,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
self
.
post_segmentio_event
(
name
=
name
)
self
.
post_segmentio_event
(
name
=
name
)
def
post_segmentio_event
(
self
,
**
kwargs
):
def
post_segmentio_event
(
self
,
**
kwargs
):
"""Post a fake
segment.io
event to the view that processes it"""
"""Post a fake
Segment
event to the view that processes it"""
request
=
self
.
create_request
(
request
=
self
.
create_request
(
data
=
self
.
create_segmentio_event_json
(
**
kwargs
),
data
=
self
.
create_segmentio_event_json
(
**
kwargs
),
content_type
=
'application/json'
content_type
=
'application/json'
...
@@ -114,7 +114,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
...
@@ -114,7 +114,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
segmentio
.
track_segmentio_event
(
request
)
segmentio
.
track_segmentio_event
(
request
)
def
create_segmentio_event
(
self
,
**
kwargs
):
def
create_segmentio_event
(
self
,
**
kwargs
):
"""Populate a fake
segment.io
event with data of interest"""
"""Populate a fake
Segment
event with data of interest"""
action
=
kwargs
.
get
(
'action'
,
'Track'
)
action
=
kwargs
.
get
(
'action'
,
'Track'
)
sample_event
=
{
sample_event
=
{
"userId"
:
kwargs
.
get
(
'user_id'
,
USER_ID
),
"userId"
:
kwargs
.
get
(
'user_id'
,
USER_ID
),
...
@@ -158,7 +158,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
...
@@ -158,7 +158,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
return
sample_event
return
sample_event
def
create_segmentio_event_json
(
self
,
**
kwargs
):
def
create_segmentio_event_json
(
self
,
**
kwargs
):
"""Return a json string containing a fake
segment.io
event"""
"""Return a json string containing a fake
Segment
event"""
return
json
.
dumps
(
self
.
create_segmentio_event
(
**
kwargs
))
return
json
.
dumps
(
self
.
create_segmentio_event
(
**
kwargs
))
@expect_failure_with_message
(
segmentio
.
WARNING_IGNORED_SOURCE
)
@expect_failure_with_message
(
segmentio
.
WARNING_IGNORED_SOURCE
)
...
...
lms/djangoapps/courseware/tests/test_views.py
View file @
a6873cb8
...
@@ -919,7 +919,7 @@ class GenerateUserCertTests(ModuleStoreTestCase):
...
@@ -919,7 +919,7 @@ class GenerateUserCertTests(ModuleStoreTestCase):
self
.
assertIn
(
"Your certificate will be available when you pass the course."
,
resp
.
content
)
self
.
assertIn
(
"Your certificate will be available when you pass the course."
,
resp
.
content
)
@patch
(
'courseware.grades.grade'
,
Mock
(
return_value
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}))
@patch
(
'courseware.grades.grade'
,
Mock
(
return_value
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}))
@override_settings
(
CERT_QUEUE
=
'certificates'
,
SEGMENT_
IO_LMS_KEY
=
"foobar"
,
FEATURES
=
{
'SEGMENT_IO_LMS'
:
True
}
)
@override_settings
(
CERT_QUEUE
=
'certificates'
,
SEGMENT_
KEY
=
"foobar"
)
def
test_user_with_passing_grade
(
self
):
def
test_user_with_passing_grade
(
self
):
# If user has above passing grading then json will return cert generating message and
# If user has above passing grading then json will return cert generating message and
# status valid code
# status valid code
...
@@ -965,7 +965,7 @@ class GenerateUserCertTests(ModuleStoreTestCase):
...
@@ -965,7 +965,7 @@ class GenerateUserCertTests(ModuleStoreTestCase):
self
.
assertIn
(
"Certificate is being created."
,
resp
.
content
)
self
.
assertIn
(
"Certificate is being created."
,
resp
.
content
)
@patch
(
'courseware.grades.grade'
,
Mock
(
return_value
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}))
@patch
(
'courseware.grades.grade'
,
Mock
(
return_value
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}))
@override_settings
(
CERT_QUEUE
=
'certificates'
,
SEGMENT_
IO_LMS_KEY
=
"foobar"
,
FEATURES
=
{
'SEGMENT_IO_LMS'
:
True
}
)
@override_settings
(
CERT_QUEUE
=
'certificates'
,
SEGMENT_
KEY
=
"foobar"
)
def
test_user_with_passing_existing_downloadable_cert
(
self
):
def
test_user_with_passing_existing_downloadable_cert
(
self
):
# If user has already downloadable certificate
# If user has already downloadable certificate
# then json will return cert generating message with bad request code
# then json will return cert generating message with bad request code
...
...
lms/djangoapps/courseware/views.py
View file @
a6873cb8
...
@@ -1383,7 +1383,7 @@ def _track_successful_certificate_generation(user_id, course_id): # pylint: dis
...
@@ -1383,7 +1383,7 @@ def _track_successful_certificate_generation(user_id, course_id): # pylint: dis
None
None
"""
"""
if
settings
.
FEATURES
.
get
(
'SEGMENT_IO_LMS'
)
and
hasattr
(
settings
,
'SEGMENT_IO_LMS_KEY'
)
:
if
settings
.
SEGMENT_KEY
:
event_name
=
'edx.bi.user.certificate.generate'
event_name
=
'edx.bi.user.certificate.generate'
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
...
...
lms/djangoapps/shoppingcart/models.py
View file @
a6873cb8
...
@@ -509,7 +509,7 @@ class Order(models.Model):
...
@@ -509,7 +509,7 @@ class Order(models.Model):
"""
"""
try
:
try
:
if
settings
.
FEATURES
.
get
(
'SEGMENT_IO_LMS'
)
and
settings
.
SEGMENT_IO_LMS
_KEY
:
if
settings
.
SEGMENT
_KEY
:
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
analytics
.
track
(
self
.
user
.
id
,
event_name
,
{
# pylint: disable=no-member
analytics
.
track
(
self
.
user
.
id
,
event_name
,
{
# pylint: disable=no-member
'orderId'
:
self
.
id
,
# pylint: disable=no-member
'orderId'
:
self
.
id
,
# pylint: disable=no-member
...
...
lms/djangoapps/shoppingcart/tests/test_models.py
View file @
a6873cb8
...
@@ -220,9 +220,8 @@ class OrderTest(ModuleStoreTestCase):
...
@@ -220,9 +220,8 @@ class OrderTest(ModuleStoreTestCase):
self
.
assertEqual
(
item
.
status
,
status
)
self
.
assertEqual
(
item
.
status
,
status
)
@override_settings
(
@override_settings
(
SEGMENT_
IO_LMS_
KEY
=
"foobar"
,
SEGMENT_KEY
=
"foobar"
,
FEATURES
=
{
FEATURES
=
{
'SEGMENT_IO_LMS'
:
True
,
'STORE_BILLING_INFO'
:
True
,
'STORE_BILLING_INFO'
:
True
,
}
}
)
)
...
@@ -884,9 +883,8 @@ class CertificateItemTest(ModuleStoreTestCase):
...
@@ -884,9 +883,8 @@ class CertificateItemTest(ModuleStoreTestCase):
self
.
assertEquals
(
cert_item
.
single_item_receipt_template
,
'shoppingcart/receipt.html'
)
self
.
assertEquals
(
cert_item
.
single_item_receipt_template
,
'shoppingcart/receipt.html'
)
@override_settings
(
@override_settings
(
SEGMENT_
IO_LMS_
KEY
=
"foobar"
,
SEGMENT_KEY
=
"foobar"
,
FEATURES
=
{
FEATURES
=
{
'SEGMENT_IO_LMS'
:
True
,
'STORE_BILLING_INFO'
:
True
,
'STORE_BILLING_INFO'
:
True
,
}
}
)
)
...
@@ -926,9 +924,8 @@ class CertificateItemTest(ModuleStoreTestCase):
...
@@ -926,9 +924,8 @@ class CertificateItemTest(ModuleStoreTestCase):
self
.
assertEquals
(
target_certs
[
0
]
.
order
.
status
,
'purchased'
)
self
.
assertEquals
(
target_certs
[
0
]
.
order
.
status
,
'purchased'
)
@override_settings
(
@override_settings
(
SEGMENT_
IO_LMS_
KEY
=
"foobar"
,
SEGMENT_KEY
=
"foobar"
,
FEATURES
=
{
FEATURES
=
{
'SEGMENT_IO_LMS'
:
True
,
'STORE_BILLING_INFO'
:
True
,
'STORE_BILLING_INFO'
:
True
,
}
}
)
)
...
...
lms/djangoapps/verify_student/tests/test_views.py
View file @
a6873cb8
...
@@ -1939,8 +1939,8 @@ class TestInCourseReverifyView(ModuleStoreTestCase):
...
@@ -1939,8 +1939,8 @@ class TestInCourseReverifyView(ModuleStoreTestCase):
url
+=
u"?{params}"
.
format
(
params
=
urllib
.
urlencode
({
"checkpoint"
:
self
.
reverification_location
}))
url
+=
u"?{params}"
.
format
(
params
=
urllib
.
urlencode
({
"checkpoint"
:
self
.
reverification_location
}))
self
.
assertRedirects
(
response
,
url
)
self
.
assertRedirects
(
response
,
url
)
@override_settings
(
SEGMENT_
IO_LMS_
KEY
=
"foobar"
)
@override_settings
(
SEGMENT_KEY
=
"foobar"
)
@patch.dict
(
settings
.
FEATURES
,
{
'AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING'
:
True
,
'SEGMENT_IO_LMS'
:
True
})
@patch.dict
(
settings
.
FEATURES
,
{
'AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING'
:
True
})
def
test_incourse_reverify_get
(
self
):
def
test_incourse_reverify_get
(
self
):
"""
"""
Test incourse reverification.
Test incourse reverification.
...
@@ -1994,8 +1994,8 @@ class TestInCourseReverifyView(ModuleStoreTestCase):
...
@@ -1994,8 +1994,8 @@ class TestInCourseReverifyView(ModuleStoreTestCase):
response
=
self
.
_submit_photos
(
self
.
course_key
,
self
.
reverification_location
,
""
)
response
=
self
.
_submit_photos
(
self
.
course_key
,
self
.
reverification_location
,
""
)
self
.
assertEqual
(
response
.
status_code
,
400
)
self
.
assertEqual
(
response
.
status_code
,
400
)
@override_settings
(
SEGMENT_
IO_LMS_
KEY
=
"foobar"
)
@override_settings
(
SEGMENT_KEY
=
"foobar"
)
@patch.dict
(
settings
.
FEATURES
,
{
'AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING'
:
True
,
'SEGMENT_IO_LMS'
:
True
})
@patch.dict
(
settings
.
FEATURES
,
{
'AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING'
:
True
})
def
test_incourse_reverify_post
(
self
):
def
test_incourse_reverify_post
(
self
):
self
.
_create_checkpoint
()
self
.
_create_checkpoint
()
self
.
_create_initial_verification
()
self
.
_create_initial_verification
()
...
...
lms/djangoapps/verify_student/views.py
View file @
a6873cb8
...
@@ -1102,7 +1102,7 @@ class SubmitPhotosView(View):
...
@@ -1102,7 +1102,7 @@ class SubmitPhotosView(View):
Returns: None
Returns: None
"""
"""
if
settings
.
FEATURES
.
get
(
'SEGMENT_IO_LMS'
)
and
hasattr
(
settings
,
'SEGMENT_IO_LMS_KEY'
)
:
if
settings
.
SEGMENT_KEY
:
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
context
=
{
context
=
{
'Google Analytics'
:
{
'Google Analytics'
:
{
...
@@ -1439,7 +1439,7 @@ class InCourseReverifyView(View):
...
@@ -1439,7 +1439,7 @@ class InCourseReverifyView(View):
event_name
,
user_id
,
course_id
,
checkpoint
event_name
,
user_id
,
course_id
,
checkpoint
)
)
if
settings
.
FEATURES
.
get
(
'SEGMENT_IO_LMS'
)
and
hasattr
(
settings
,
'SEGMENT_IO_LMS_KEY'
)
:
if
settings
.
SEGMENT_KEY
:
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
analytics
.
track
(
analytics
.
track
(
user_id
,
user_id
,
...
...
lms/envs/aws.py
View file @
a6873cb8
...
@@ -400,10 +400,7 @@ if 'DJFS' in AUTH_TOKENS and AUTH_TOKENS['DJFS'] is not None:
...
@@ -400,10 +400,7 @@ if 'DJFS' in AUTH_TOKENS and AUTH_TOKENS['DJFS'] is not None:
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS
=
ENV_TOKENS
.
get
(
'HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS'
,
{})
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS
=
ENV_TOKENS
.
get
(
'HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS'
,
{})
############### Mixed Related(Secure/Not-Secure) Items ##########
############### Mixed Related(Secure/Not-Secure) Items ##########
# If Segment.io key specified, load it and enable Segment.io if the feature flag is set
SEGMENT_KEY
=
AUTH_TOKENS
.
get
(
'SEGMENT_KEY'
)
SEGMENT_IO_LMS_KEY
=
AUTH_TOKENS
.
get
(
'SEGMENT_IO_LMS_KEY'
)
if
SEGMENT_IO_LMS_KEY
:
FEATURES
[
'SEGMENT_IO_LMS'
]
=
ENV_TOKENS
.
get
(
'SEGMENT_IO_LMS'
,
False
)
CC_PROCESSOR_NAME
=
AUTH_TOKENS
.
get
(
'CC_PROCESSOR_NAME'
,
CC_PROCESSOR_NAME
)
CC_PROCESSOR_NAME
=
AUTH_TOKENS
.
get
(
'CC_PROCESSOR_NAME'
,
CC_PROCESSOR_NAME
)
CC_PROCESSOR
=
AUTH_TOKENS
.
get
(
'CC_PROCESSOR'
,
CC_PROCESSOR
)
CC_PROCESSOR
=
AUTH_TOKENS
.
get
(
'CC_PROCESSOR'
,
CC_PROCESSOR
)
...
...
lms/envs/bok_choy.env.json
View file @
a6873cb8
...
@@ -112,7 +112,6 @@
...
@@ -112,7 +112,6 @@
"city"
:
"hidden"
,
"city"
:
"hidden"
,
"country"
:
"required"
"country"
:
"required"
},
},
"SEGMENT_IO_LMS"
:
true
,
"SERVER_EMAIL"
:
"devops@example.com"
,
"SERVER_EMAIL"
:
"devops@example.com"
,
"SESSION_COOKIE_DOMAIN"
:
null
,
"SESSION_COOKIE_DOMAIN"
:
null
,
"SITE_NAME"
:
"localhost:8003"
,
"SITE_NAME"
:
"localhost:8003"
,
...
...
lms/envs/common.py
View file @
a6873cb8
...
@@ -182,9 +182,6 @@ FEATURES = {
...
@@ -182,9 +182,6 @@ FEATURES = {
# Staff Debug tool.
# Staff Debug tool.
'ENABLE_STUDENT_HISTORY_VIEW'
:
True
,
'ENABLE_STUDENT_HISTORY_VIEW'
:
True
,
# Segment.io for LMS--need to explicitly turn it on for production.
'SEGMENT_IO_LMS'
:
False
,
# Provide a UI to allow users to submit feedback from the LMS (left-hand help modal)
# Provide a UI to allow users to submit feedback from the LMS (left-hand help modal)
'ENABLE_FEEDBACK_SUBMISSION'
:
False
,
'ENABLE_FEEDBACK_SUBMISSION'
:
False
,
...
@@ -611,6 +608,7 @@ USAGE_ID_PATTERN = r'(?P<usage_id>(?:i4x://?[^/]+/[^/]+/[^/]+/[^@]+(?:@[^/]+)?)|
...
@@ -611,6 +608,7 @@ USAGE_ID_PATTERN = r'(?P<usage_id>(?:i4x://?[^/]+/[^/]+/[^/]+/[^@]+(?:@[^/]+)?)|
############################## EVENT TRACKING #################################
############################## EVENT TRACKING #################################
SEGMENT_KEY
=
None
# FIXME: Should we be doing this truncation?
# FIXME: Should we be doing this truncation?
TRACK_MAX_EVENT
=
50000
TRACK_MAX_EVENT
=
50000
...
...
lms/envs/dev.py
View file @
a6873cb8
...
@@ -272,12 +272,10 @@ PIPELINE_SASS_ARGUMENTS = '--debug-info --require {proj_dir}/static/sass/bourbon
...
@@ -272,12 +272,10 @@ PIPELINE_SASS_ARGUMENTS = '--debug-info --require {proj_dir}/static/sass/bourbon
ANALYTICS_SERVER_URL
=
"http://127.0.0.1:9000/"
ANALYTICS_SERVER_URL
=
"http://127.0.0.1:9000/"
ANALYTICS_API_KEY
=
""
ANALYTICS_API_KEY
=
""
##### Segment
.io
######
##### Segment ######
# If there's an environment variable set, grab it and turn on Segment.io
# If there's an environment variable set, grab it
SEGMENT_IO_LMS_KEY
=
os
.
environ
.
get
(
'SEGMENT_IO_LMS_KEY'
)
SEGMENT_KEY
=
os
.
environ
.
get
(
'SEGMENT_KEY'
)
if
SEGMENT_IO_LMS_KEY
:
FEATURES
[
'SEGMENT_IO_LMS'
]
=
True
###################### Payment ######################
###################### Payment ######################
...
...
lms/envs/yaml_config.py
View file @
a6873cb8
...
@@ -94,7 +94,6 @@ GIT_IMPORT_STATIC = True
...
@@ -94,7 +94,6 @@ GIT_IMPORT_STATIC = True
META_UNIVERSITIES
=
{}
META_UNIVERSITIES
=
{}
DATADOG
=
{}
DATADOG
=
{}
EMAIL_FILE_PATH
=
None
EMAIL_FILE_PATH
=
None
SEGMENT_IO_LMS
=
False
MONGODB_LOG
=
{}
MONGODB_LOG
=
{}
SESSION_INACTIVITY_TIMEOUT_IN_SECONDS
=
None
SESSION_INACTIVITY_TIMEOUT_IN_SECONDS
=
None
...
@@ -283,8 +282,6 @@ vars().update(AUTH_TOKENS)
...
@@ -283,8 +282,6 @@ vars().update(AUTH_TOKENS)
# Manipulate imported settings with code
# Manipulate imported settings with code
#
#
FEATURES
[
'SEGMENT_IO_LMS'
]
=
SEGMENT_IO_LMS
if
AWS_ACCESS_KEY_ID
==
""
:
if
AWS_ACCESS_KEY_ID
==
""
:
AWS_ACCESS_KEY_ID
=
None
AWS_ACCESS_KEY_ID
=
None
...
...
lms/startup.py
View file @
a6873cb8
...
@@ -38,10 +38,9 @@ def run():
...
@@ -38,10 +38,9 @@ def run():
if
settings
.
FEATURES
.
get
(
'ENABLE_THIRD_PARTY_AUTH'
,
False
):
if
settings
.
FEATURES
.
get
(
'ENABLE_THIRD_PARTY_AUTH'
,
False
):
enable_third_party_auth
()
enable_third_party_auth
()
# Initialize Segment.io analytics module. Flushes first time a message is received and
# Initialize Segment analytics module by setting the write_key.
# every 50 messages thereafter, or if 10 seconds have passed since last flush
if
settings
.
SEGMENT_KEY
:
if
settings
.
FEATURES
.
get
(
'SEGMENT_IO_LMS'
)
and
hasattr
(
settings
,
'SEGMENT_IO_LMS_KEY'
)
and
settings
.
SEGMENT_IO_LMS_KEY
:
# pylint: disable=line-too-long
analytics
.
write_key
=
settings
.
SEGMENT_KEY
analytics
.
write_key
=
settings
.
SEGMENT_IO_LMS_KEY
# register any dependency injections that we need to support in edx_proctoring
# register any dependency injections that we need to support in edx_proctoring
# right now edx_proctoring is dependent on the openedx.core.djangoapps.credit
# right now edx_proctoring is dependent on the openedx.core.djangoapps.credit
...
...
lms/templates/widgets/segment-io.html
View file @
a6873cb8
% if settings.
FEATURES.get('SEGMENT_IO_LMS')
:
% if settings.
SEGMENT_KEY
:
<!-- begin Segment
.io
-->
<!-- begin Segment -->
<script
type=
"text/javascript"
>
<script
type=
"text/javascript"
>
// Asynchronously load Segment
.io
's analytics.js library
// Asynchronously load Segment's analytics.js library
window
.
analytics
||
(
window
.
analytics
=
[]),
window
.
analytics
.
methods
=
[
"identify"
,
"track"
,
"trackLink"
,
"trackForm"
,
"trackClick"
,
"trackSubmit"
,
"page"
,
"pageview"
,
"ab"
,
"alias"
,
"ready"
,
"group"
,
"on"
,
"once"
,
"off"
],
window
.
analytics
.
factory
=
function
(
t
){
return
function
(){
var
a
=
Array
.
prototype
.
slice
.
call
(
arguments
);
return
a
.
unshift
(
t
),
window
.
analytics
.
push
(
a
),
window
.
analytics
}};
for
(
var
i
=
0
;
i
<
window
.
analytics
.
methods
.
length
;
i
++
){
var
method
=
window
.
analytics
.
methods
[
i
];
window
.
analytics
[
method
]
=
window
.
analytics
.
factory
(
method
)}
window
.
analytics
.
load
=
function
(
t
){
var
a
=
document
.
createElement
(
"script"
);
a
.
type
=
"text/javascript"
,
a
.
async
=!
0
,
a
.
src
=
(
"https:"
===
document
.
location
.
protocol
?
"https://"
:
"http://"
)
+
"d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/"
+
t
+
"/analytics.min.js"
;
var
n
=
document
.
getElementsByTagName
(
"script"
)[
0
];
n
.
parentNode
.
insertBefore
(
a
,
n
)},
window
.
analytics
.
SNIPPET_VERSION
=
"2.0.8"
,
window
.
analytics
||
(
window
.
analytics
=
[]),
window
.
analytics
.
methods
=
[
"identify"
,
"track"
,
"trackLink"
,
"trackForm"
,
"trackClick"
,
"trackSubmit"
,
"page"
,
"pageview"
,
"ab"
,
"alias"
,
"ready"
,
"group"
,
"on"
,
"once"
,
"off"
],
window
.
analytics
.
factory
=
function
(
t
){
return
function
(){
var
a
=
Array
.
prototype
.
slice
.
call
(
arguments
);
return
a
.
unshift
(
t
),
window
.
analytics
.
push
(
a
),
window
.
analytics
}};
for
(
var
i
=
0
;
i
<
window
.
analytics
.
methods
.
length
;
i
++
){
var
method
=
window
.
analytics
.
methods
[
i
];
window
.
analytics
[
method
]
=
window
.
analytics
.
factory
(
method
)}
window
.
analytics
.
load
=
function
(
t
){
var
a
=
document
.
createElement
(
"script"
);
a
.
type
=
"text/javascript"
,
a
.
async
=!
0
,
a
.
src
=
(
"https:"
===
document
.
location
.
protocol
?
"https://"
:
"http://"
)
+
"d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/"
+
t
+
"/analytics.min.js"
;
var
n
=
document
.
getElementsByTagName
(
"script"
)[
0
];
n
.
parentNode
.
insertBefore
(
a
,
n
)},
window
.
analytics
.
SNIPPET_VERSION
=
"2.0.8"
,
analytics
.
load
(
"${ settings.SEGMENT_
IO_LMS_
KEY }"
);
analytics
.
load
(
"${ settings.SEGMENT_KEY }"
);
analytics
.
page
();
analytics
.
page
();
%
if
user
.
is_authenticated
():
%
if
user
.
is_authenticated
():
...
@@ -13,9 +13,9 @@
...
@@ -13,9 +13,9 @@
});
});
%
endif
%
endif
</script>
</script>
<!-- end Segment
.io
-->
<!-- end Segment -->
% else:
% else:
<!-- dummy
segment.io
-->
<!-- dummy
Segment
-->
<script
type=
"text/javascript"
>
<script
type=
"text/javascript"
>
var
analytics
=
{
var
analytics
=
{
track
:
function
()
{
return
;
},
track
:
function
()
{
return
;
},
...
@@ -24,5 +24,5 @@
...
@@ -24,5 +24,5 @@
page
:
function
()
{
return
;
}
page
:
function
()
{
return
;
}
};
};
</script>
</script>
<!-- end dummy
segment.io
-->
<!-- end dummy
Segment
-->
% endif
% endif
openedx/core/djangoapps/user_api/preferences/api.py
View file @
a6873cb8
...
@@ -261,7 +261,7 @@ def update_email_opt_in(user, org, opt_in):
...
@@ -261,7 +261,7 @@ def update_email_opt_in(user, org, opt_in):
preference
.
value
=
str
(
opt_in
)
preference
.
value
=
str
(
opt_in
)
try
:
try
:
preference
.
save
()
preference
.
save
()
if
settings
.
FEATURES
.
get
(
'SEGMENT_IO_LMS'
)
and
settings
.
SEGMENT_IO_LMS
_KEY
:
if
settings
.
SEGMENT
_KEY
:
_track_update_email_opt_in
(
user
.
id
,
org
,
opt_in
)
_track_update_email_opt_in
(
user
.
id
,
org
,
opt_in
)
except
IntegrityError
as
err
:
except
IntegrityError
as
err
:
log
.
warn
(
u"Could not update organization wide preference due to IntegrityError: {}"
.
format
(
err
.
message
))
log
.
warn
(
u"Could not update organization wide preference due to IntegrityError: {}"
.
format
(
err
.
message
))
...
...
requirements/edx/base.txt
View file @
a6873cb8
...
@@ -146,7 +146,7 @@ selenium==2.42.1
...
@@ -146,7 +146,7 @@ selenium==2.42.1
splinter==0.5.4
splinter==0.5.4
testtools==0.9.34
testtools==0.9.34
# Used for Segment
.io
analytics
# Used for Segment analytics
analytics-python==1.1.0
analytics-python==1.1.0
# Needed for mailchimp(mailing djangoapp)
# Needed for mailchimp(mailing djangoapp)
...
...
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