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
d1d44e7b
Commit
d1d44e7b
authored
Sep 10, 2015
by
Daniel Friedman
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #9611 from edx/dan-f/add-team-page-viewed-events
Add page viewed events to teams app.
parents
83e6da06
3b957a7e
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
276 additions
and
26 deletions
+276
-26
common/test/acceptance/tests/lms/test_teams.py
+116
-3
lms/djangoapps/teams/static/teams/js/spec/views/teams_tab_spec.js
+82
-8
lms/djangoapps/teams/static/teams/js/utils/team_analytics.js
+23
-0
lms/djangoapps/teams/static/teams/js/views/teams_tab.js
+11
-5
lms/djangoapps/teams/static/teams/js/views/teams_tabbed_view.js
+24
-0
lms/static/js/components/tabbed/views/tabbed_view.js
+20
-10
No files found.
common/test/acceptance/tests/lms/test_teams.py
View file @
d1d44e7b
...
...
@@ -7,7 +7,6 @@ import time
from
dateutil.parser
import
parse
import
ddt
from
flaky
import
flaky
from
nose.plugins.attrib
import
attr
from
uuid
import
uuid4
from
unittest
import
skip
...
...
@@ -286,6 +285,14 @@ class MyTeamsTest(TeamsTabBase):
self
.
topic
=
{
u"name"
:
u"Example Topic"
,
u"id"
:
"example_topic"
,
u"description"
:
"Description"
}
self
.
set_team_configuration
({
'course_id'
:
self
.
course_id
,
'max_team_size'
:
10
,
'topics'
:
[
self
.
topic
]})
self
.
my_teams_page
=
MyTeamsPage
(
self
.
browser
,
self
.
course_id
)
self
.
page_viewed_event
=
{
'event_type'
:
'edx.team.page_viewed'
,
'event'
:
{
'page_name'
:
'my-teams'
,
'topic_id'
:
None
,
'team_id'
:
None
}
}
def
test_not_member_of_any_teams
(
self
):
"""
...
...
@@ -295,7 +302,8 @@ class MyTeamsTest(TeamsTabBase):
And I should see no teams
And I should see a message that I belong to no teams.
"""
self
.
my_teams_page
.
visit
()
with
self
.
assert_events_match_during
(
self
.
only_team_events
,
expected_events
=
[
self
.
page_viewed_event
]):
self
.
my_teams_page
.
visit
()
self
.
assertEqual
(
len
(
self
.
my_teams_page
.
team_cards
),
0
,
msg
=
'Expected to see no team cards'
)
self
.
assertEqual
(
self
.
my_teams_page
.
q
(
css
=
'.page-content-main'
)
.
text
,
...
...
@@ -313,7 +321,8 @@ class MyTeamsTest(TeamsTabBase):
"""
teams
=
self
.
create_teams
(
self
.
topic
,
1
)
self
.
create_membership
(
self
.
user_info
[
'username'
],
teams
[
0
][
'id'
])
self
.
my_teams_page
.
visit
()
with
self
.
assert_events_match_during
(
self
.
only_team_events
,
expected_events
=
[
self
.
page_viewed_event
]):
self
.
my_teams_page
.
visit
()
self
.
verify_teams
(
self
.
my_teams_page
,
teams
)
...
...
@@ -511,6 +520,28 @@ class BrowseTopicsTest(TeamsTabBase):
self
.
assertEqual
(
browse_teams_page
.
header_name
,
'Example Topic'
)
self
.
assertEqual
(
browse_teams_page
.
header_description
,
'Description'
)
def
test_page_viewed_event
(
self
):
"""
Scenario: Visiting the browse topics page should fire a page viewed event.
Given I am enrolled in a course with a team configuration and a topic
When I visit the browse topics page
Then my browser should post a page viewed event
"""
topic
=
{
u"name"
:
u"Example Topic"
,
u"id"
:
u"example_topic"
,
u"description"
:
"Description"
}
self
.
set_team_configuration
(
{
u"max_team_size"
:
1
,
u"topics"
:
[
topic
]}
)
events
=
[{
'event_type'
:
'edx.team.page_viewed'
,
'event'
:
{
'page_name'
:
'browse'
,
'topic_id'
:
None
,
'team_id'
:
None
}
}]
with
self
.
assert_events_match_during
(
self
.
only_team_events
,
expected_events
=
events
):
self
.
topics_page
.
visit
()
@attr
(
'shard_5'
)
@ddt.ddt
...
...
@@ -752,6 +783,7 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
Then I should see the search result page
And the search header should be shown
And 0 results should be shown
And my browser should fire a page viewed event for the search page
"""
# Note: all searches will return 0 results with the mock search server
# used by Bok Choy.
...
...
@@ -766,12 +798,38 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
'topic_id'
:
self
.
topic
[
'id'
],
'number_of_results'
:
0
}
},
{
'event_type'
:
'edx.team.page_viewed'
,
'event'
:
{
'page_name'
:
'search-teams'
,
'topic_id'
:
self
.
topic
[
'id'
],
'team_id'
:
None
}
}]
with
self
.
assert_events_match_during
(
self
.
only_team_events
,
expected_events
=
events
):
search_results_page
=
self
.
browse_teams_page
.
search
(
search_text
)
self
.
verify_search_header
(
search_results_page
,
search_text
)
self
.
assertTrue
(
search_results_page
.
get_pagination_header_text
()
.
startswith
(
'Showing 0 out of 0 total'
))
def
test_page_viewed_event
(
self
):
"""
Scenario: Visiting the browse page should fire a page viewed event.
Given I am enrolled in a course with a team configuration and a topic
When I visit the Teams page
Then my browser should post a page viewed event for the teams page
"""
self
.
create_teams
(
self
.
topic
,
5
)
events
=
[{
'event_type'
:
'edx.team.page_viewed'
,
'event'
:
{
'page_name'
:
'single-topic'
,
'topic_id'
:
self
.
topic
[
'id'
],
'team_id'
:
None
}
}]
with
self
.
assert_events_match_during
(
self
.
only_team_events
,
expected_events
=
events
):
self
.
browse_teams_page
.
visit
()
@attr
(
'shard_5'
)
class
TeamFormActions
(
TeamsTabBase
):
...
...
@@ -1024,6 +1082,24 @@ class CreateTeamTest(TeamFormActions):
self
.
verify_my_team_count
(
0
)
def
test_page_viewed_event
(
self
):
"""
Scenario: Visiting the create team page should fire a page viewed event.
Given I am enrolled in a course with a team configuration and a topic
When I visit the create team page
Then my browser should post a page viewed event
"""
events
=
[{
'event_type'
:
'edx.team.page_viewed'
,
'event'
:
{
'page_name'
:
'new-team'
,
'topic_id'
:
self
.
topic
[
'id'
],
'team_id'
:
None
}
}]
with
self
.
assert_events_match_during
(
self
.
only_team_events
,
expected_events
=
events
):
self
.
verify_and_navigate_to_create_team_page
()
@ddt.ddt
class
EditTeamTest
(
TeamFormActions
):
...
...
@@ -1224,6 +1300,24 @@ class EditTeamTest(TeamFormActions):
language
=
'English'
)
def
test_page_viewed_event
(
self
):
"""
Scenario: Visiting the edit team page should fire a page viewed event.
Given I am enrolled in a course with a team configuration and a topic
When I visit the edit team page
Then my browser should post a page viewed event
"""
events
=
[{
'event_type'
:
'edx.team.page_viewed'
,
'event'
:
{
'page_name'
:
'edit-team'
,
'topic_id'
:
self
.
topic
[
'id'
],
'team_id'
:
self
.
team
[
'id'
]
}
}]
with
self
.
assert_events_match_during
(
self
.
only_team_events
,
expected_events
=
events
):
self
.
verify_and_navigate_to_edit_team_page
()
@attr
(
'shard_5'
)
@ddt.ddt
...
...
@@ -1554,3 +1648,22 @@ class TeamPageTest(TeamsTabBase):
# Verify that if one switches to "My Team" without reloading the page, the old team no longer shows.
self
.
teams_page
.
click_all_topics
()
self
.
verify_my_team_count
(
0
)
def
test_page_viewed_event
(
self
):
"""
Scenario: Visiting the team profile page should fire a page viewed event.
Given I am enrolled in a course with a team configuration and a topic
When I visit the team profile page
Then my browser should post a page viewed event
"""
self
.
_set_team_configuration_and_membership
()
events
=
[{
'event_type'
:
'edx.team.page_viewed'
,
'event'
:
{
'page_name'
:
'single-team'
,
'topic_id'
:
self
.
topic
[
'id'
],
'team_id'
:
self
.
teams
[
0
][
'id'
]
}
}]
with
self
.
assert_events_match_during
(
self
.
only_team_events
,
expected_events
=
events
):
self
.
team_page
.
visit
()
lms/djangoapps/teams/static/teams/js/spec/views/teams_tab_spec.js
View file @
d1d44e7b
define
([
'jquery'
,
'backbone'
,
'logger'
,
'common/js/spec_helpers/ajax_helpers'
,
'common/js/spec_helpers/spec_helpers'
,
'teams/js/views/teams_tab'
,
'teams/js/spec_helpers/team_spec_helpers'
],
function
(
$
,
Backbone
,
Ajax
Helpers
,
TeamsTabView
,
TeamSpecHelpers
)
{
],
function
(
$
,
Backbone
,
Logger
,
AjaxHelpers
,
Spec
Helpers
,
TeamsTabView
,
TeamSpecHelpers
)
{
'use strict'
;
describe
(
'TeamsTab'
,
function
()
{
...
...
@@ -34,14 +36,34 @@ define([
return
teamsTabView
;
};
/**
* Filters out all team events from a list of requests.
*/
var
removeTeamEvents
=
function
(
requests
)
{
return
requests
.
filter
(
function
(
request
)
{
if
(
request
.
requestBody
&&
request
.
requestBody
.
startsWith
(
'event_type=edx.team'
))
{
return
false
;
}
else
{
return
true
;
}
});
};
beforeEach
(
function
()
{
setFixtures
(
'<div class="teams-content"></div>'
);
spyOn
(
$
.
fn
,
'focus'
);
spyOn
(
Logger
,
'log'
);
});
afterEach
(
Backbone
.
history
.
stop
);
describe
(
'Navigation'
,
function
()
{
it
(
'does not interfere with anchor links to #content'
,
function
()
{
var
teamsTabView
=
createTeamsTabView
();
teamsTabView
.
router
.
navigate
(
'#content'
,
{
trigger
:
true
});
expect
(
teamsTabView
.
$
(
'.warning'
)).
toHaveClass
(
'is-hidden'
);
});
it
(
'displays and focuses an error message when trying to navigate to a nonexistent page'
,
function
()
{
var
teamsTabView
=
createTeamsTabView
();
teamsTabView
.
router
.
navigate
(
'no_such_page'
,
{
trigger
:
true
});
...
...
@@ -49,12 +71,6 @@ define([
expectFocus
(
teamsTabView
.
$
(
'.warning'
));
});
it
(
'does not interfere with anchor links to #content'
,
function
()
{
var
teamsTabView
=
createTeamsTabView
();
teamsTabView
.
router
.
navigate
(
'#content'
,
{
trigger
:
true
});
expect
(
teamsTabView
.
$
(
'.warning'
)).
toHaveClass
(
'is-hidden'
);
});
it
(
'displays and focuses an error message when trying to navigate to a nonexistent topic'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
),
teamsTabView
=
createTeamsTabView
();
...
...
@@ -94,6 +110,64 @@ define([
});
});
describe
(
'Analytics Events'
,
function
()
{
SpecHelpers
.
withData
({
'fires a page view event for the topic page'
:
[
'topics/'
+
TeamSpecHelpers
.
testTopicID
,
{
page_name
:
'single-topic'
,
topic_id
:
TeamSpecHelpers
.
testTopicID
,
team_id
:
null
}
],
'fires a page view event for the team page'
:
[
'teams/'
+
TeamSpecHelpers
.
testTopicID
+
'/test_team_id'
,
{
page_name
:
'single-team'
,
topic_id
:
TeamSpecHelpers
.
testTopicID
,
team_id
:
'test_team_id'
}
],
'fires a page view event for the search team page'
:
[
'topics/'
+
TeamSpecHelpers
.
testTopicID
+
'/search'
,
{
page_name
:
'search-teams'
,
topic_id
:
TeamSpecHelpers
.
testTopicID
,
team_id
:
null
}
],
'fires a page view event for the new team page'
:
[
'topics/'
+
TeamSpecHelpers
.
testTopicID
+
'/create-team'
,
{
page_name
:
'new-team'
,
topic_id
:
TeamSpecHelpers
.
testTopicID
,
team_id
:
null
}
],
'fires a page view event for the edit team page'
:
[
'topics/'
+
TeamSpecHelpers
.
testTopicID
+
'/'
+
'test_team_id/edit-team'
,
{
page_name
:
'edit-team'
,
topic_id
:
TeamSpecHelpers
.
testTopicID
,
team_id
:
'test_team_id'
}
]
},
function
(
url
,
expectedEvent
)
{
if
(
url
.
indexOf
(
'search'
)
!==
-
1
||
url
.
indexOf
(
'create-team'
)
!==
-
1
||
url
.
indexOf
(
'edit-team'
)
!==
-
1
)
{
debugger
;
}
var
requests
=
AjaxHelpers
.
requests
(
this
),
teamsTabView
=
createTeamsTabView
();
teamsTabView
.
router
.
navigate
(
url
,
{
trigger
:
true
});
if
(
requests
.
length
)
{
AjaxHelpers
.
respondWithJson
(
requests
,
{});
}
expect
(
Logger
.
log
).
toHaveBeenCalledWith
(
'edx.team.page_viewed'
,
expectedEvent
);
});
});
describe
(
'Discussion privileges'
,
function
()
{
it
(
'allows privileged access to any team'
,
function
()
{
var
teamsTabView
=
createTeamsTabView
({
...
...
@@ -206,7 +280,7 @@ define([
// Navigate back to the teams list
teamsTabView
.
$
(
'.breadcrumbs a'
).
last
().
click
();
verifyTeamsRequest
(
re
quests
,
{
verifyTeamsRequest
(
re
moveTeamEvents
(
requests
)
,
{
order_by
:
'last_activity_at'
,
text_search
:
''
});
...
...
lms/djangoapps/teams/static/teams/js/utils/team_analytics.js
0 → 100644
View file @
d1d44e7b
/**
* Utility methods for emitting teams events. See the event spec:
* https://openedx.atlassian.net/wiki/display/AN/Teams+Feature+Event+Design
*/
;(
function
(
define
)
{
'use strict'
;
define
([
'logger'
],
function
(
Logger
)
{
var
TeamAnalytics
=
{
emitPageViewed
:
function
(
page_name
,
topic_id
,
team_id
)
{
Logger
.
log
(
'edx.team.page_viewed'
,
{
page_name
:
page_name
,
topic_id
:
topic_id
,
team_id
:
team_id
});
}
};
return
TeamAnalytics
;
});
}).
call
(
this
,
define
||
RequireJS
.
define
);
lms/djangoapps/teams/static/teams/js/views/teams_tab.js
View file @
d1d44e7b
...
...
@@ -7,12 +7,13 @@
'common/js/components/views/search_field'
,
'js/components/header/views/header'
,
'js/components/header/models/header'
,
'js/components/tabbed/views/tabbed_view'
,
'teams/js/models/topic'
,
'teams/js/collections/topic'
,
'teams/js/models/team'
,
'teams/js/collections/team'
,
'teams/js/collections/team_membership'
,
'teams/js/utils/team_analytics'
,
'teams/js/views/teams_tabbed_view'
,
'teams/js/views/topics'
,
'teams/js/views/team_profile'
,
'teams/js/views/my_teams'
,
...
...
@@ -21,9 +22,9 @@
'teams/js/views/team_profile_header_actions'
,
'teams/js/views/team_utils'
,
'text!teams/templates/teams_tab.underscore'
],
function
(
Backbone
,
_
,
gettext
,
SearchFieldView
,
HeaderView
,
HeaderModel
,
TabbedView
,
TopicModel
,
TopicCollection
,
TeamModel
,
TeamCollection
,
TeamMembershipCollection
,
TopicsView
,
TeamProfileView
,
MyTeamsView
,
TopicTeamsView
,
TeamEditView
,
function
(
Backbone
,
_
,
gettext
,
SearchFieldView
,
HeaderView
,
HeaderModel
,
TopicModel
,
TopicCollection
,
TeamModel
,
TeamCollection
,
TeamMembershipCollection
,
TeamAnalytics
,
T
eamsTabbedView
,
T
opicsView
,
TeamProfileView
,
MyTeamsView
,
TopicTeamsView
,
TeamEditView
,
TeamProfileHeaderActionsView
,
TeamUtils
,
teamsTemplate
)
{
var
TeamsHeaderModel
=
HeaderModel
.
extend
({
initialize
:
function
()
{
...
...
@@ -118,7 +119,7 @@
this
.
mainView
=
this
.
tabbedView
=
this
.
createViewWithHeader
({
title
:
gettext
(
"Teams"
),
description
:
gettext
(
"See all teams in your course, organized by topic. Join a team to collaborate with other learners who are interested in the same topic as you are."
),
mainView
:
new
TabbedView
({
mainView
:
new
T
eamsT
abbedView
({
tabs
:
[{
title
:
gettext
(
'My Team'
),
url
:
'my-teams'
,
...
...
@@ -180,6 +181,7 @@
this
.
getTeamsView
(
topicID
).
done
(
function
(
teamsView
)
{
self
.
teamsView
=
self
.
mainView
=
teamsView
;
self
.
render
();
TeamAnalytics
.
emitPageViewed
(
'single-topic'
,
topicID
,
null
);
});
},
...
...
@@ -205,6 +207,7 @@
showSortControls
:
false
});
view
.
render
();
TeamAnalytics
.
emitPageViewed
(
'search-teams'
,
topicID
,
null
);
});
}
},
...
...
@@ -227,6 +230,7 @@
})
});
view
.
render
();
TeamAnalytics
.
emitPageViewed
(
'new-team'
,
topicID
,
null
);
});
},
...
...
@@ -254,6 +258,7 @@
});
self
.
mainView
=
editViewWithHeader
;
self
.
render
();
TeamAnalytics
.
emitPageViewed
(
'edit-team'
,
topicID
,
teamID
);
});
});
},
...
...
@@ -340,6 +345,7 @@
this
.
getBrowseTeamView
(
topicID
,
teamID
).
done
(
function
(
browseTeamView
)
{
self
.
mainView
=
browseTeamView
;
self
.
render
();
TeamAnalytics
.
emitPageViewed
(
'single-team'
,
topicID
,
teamID
);
});
},
...
...
lms/djangoapps/teams/static/teams/js/views/teams_tabbed_view.js
0 → 100644
View file @
d1d44e7b
/**
* A custom TabbedView for Teams.
*/
;(
function
(
define
)
{
'use strict'
;
define
([
'js/components/tabbed/views/tabbed_view'
,
'teams/js/utils/team_analytics'
],
function
(
TabbedView
,
TeamAnalytics
)
{
var
TeamsTabbedView
=
TabbedView
.
extend
({
/**
* Overrides TabbedView.prototype.setActiveTab in order to
* log page viewed events.
*/
setActiveTab
:
function
(
index
)
{
TabbedView
.
prototype
.
setActiveTab
.
call
(
this
,
index
);
TeamAnalytics
.
emitPageViewed
(
this
.
getTabMeta
(
index
).
tab
.
url
,
null
,
null
);
}
});
return
TeamsTabbedView
;
});
}).
call
(
this
,
define
||
RequireJS
.
define
);
lms/static/js/components/tabbed/views/tabbed_view.js
View file @
d1d44e7b
...
...
@@ -59,16 +59,10 @@
},
setActiveTab
:
function
(
index
)
{
var
tab
,
tabEl
,
view
;
if
(
typeof
index
===
'string'
)
{
tab
=
this
.
urlMap
[
index
];
tabEl
=
this
.
$
(
'a[data-url='
+
index
+
']'
);
}
else
{
tab
=
this
.
tabs
[
index
];
tabEl
=
this
.
$
(
'a[data-index='
+
index
+
']'
);
}
view
=
tab
.
view
;
var
tabMeta
=
this
.
getTabMeta
(
index
),
tab
=
tabMeta
.
tab
,
tabEl
=
tabMeta
.
element
,
view
=
tab
.
view
;
this
.
$
(
'a.is-active'
).
removeClass
(
'is-active'
).
attr
(
'aria-selected'
,
'false'
);
tabEl
.
addClass
(
'is-active'
).
attr
(
'aria-selected'
,
'true'
);
view
.
setElement
(
this
.
$
(
'.page-content-main'
)).
render
();
...
...
@@ -81,6 +75,22 @@
switchTab
:
function
(
event
)
{
event
.
preventDefault
();
this
.
setActiveTab
(
$
(
event
.
currentTarget
).
data
(
'index'
));
},
/**
* Get the tab by name or index. Returns an object
* encapsulating the tab object and its element.
*/
getTabMeta
:
function
(
tabNameOrIndex
)
{
var
tab
,
element
;
if
(
typeof
tabNameOrIndex
===
'string'
)
{
tab
=
this
.
urlMap
[
tabNameOrIndex
];
element
=
this
.
$
(
'a[data-url='
+
tabNameOrIndex
+
']'
);
}
else
{
tab
=
this
.
tabs
[
tabNameOrIndex
];
element
=
this
.
$
(
'a[data-index='
+
tabNameOrIndex
+
']'
);
}
return
{
'tab'
:
tab
,
'element'
:
element
};
}
});
return
TabbedView
;
...
...
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