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
8c1bf2cd
Commit
8c1bf2cd
authored
Sep 03, 2015
by
Diana Huang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add events for tracking when teams are edited.
TNL-3190
parent
deacfebd
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
139 additions
and
18 deletions
+139
-18
common/djangoapps/util/model_utils.py
+33
-16
common/test/acceptance/tests/lms/test_teams.py
+50
-1
lms/djangoapps/teams/models.py
+6
-0
lms/djangoapps/teams/tests/test_views.py
+28
-1
lms/djangoapps/teams/views.py
+22
-0
No files found.
common/djangoapps/util/model_utils.py
View file @
8c1bf2cd
...
...
@@ -99,18 +99,19 @@ def emit_field_changed_events(instance, user, db_table, excluded_fields=None, hi
del
instance
.
_changed_fields
def
emit_setting_changed_event
(
user
,
db_table
,
setting_name
,
old_value
,
new_value
):
"""Emits an event for a change in a setting.
def
truncate_fields
(
old_value
,
new_value
):
"""
Truncates old_value and new_value for analytics event emission if necessary.
Args:
user (User): the user that this setting is associated with.
db_table (str): the name of the table that we're modifying.
setting_name (str): the name of the setting being changed.
old_value (object): the value before the change.
new_value (object): the new value being saved.
old_value(obj): the value before the change
new_value(obj): the new value being saved
Returns:
None
a dictionary with the following fields:
'old': the truncated old value
'new': the truncated new value
'truncated': the list of fields that have been truncated
"""
# Compute the maximum value length so that two copies can fit into the maximum event size
# in addition to all the other fields recorded.
...
...
@@ -123,16 +124,32 @@ def emit_setting_changed_event(user, db_table, setting_name, old_value, new_valu
truncated_values
.
append
(
"old"
)
if
new_was_truncated
:
truncated_values
.
append
(
"new"
)
return
{
'old'
:
serialized_old_value
,
'new'
:
serialized_new_value
,
'truncated'
:
truncated_values
}
def
emit_setting_changed_event
(
user
,
db_table
,
setting_name
,
old_value
,
new_value
):
"""Emits an event for a change in a setting.
Args:
user (User): the user that this setting is associated with.
db_table (str): the name of the table that we're modifying.
setting_name (str): the name of the setting being changed.
old_value (object): the value before the change.
new_value (object): the new value being saved.
Returns:
None
"""
truncated_fields
=
truncate_fields
(
old_value
,
new_value
)
truncated_fields
[
'setting'
]
=
setting_name
truncated_fields
[
'user_id'
]
=
user
.
id
truncated_fields
[
'table'
]
=
db_table
tracker
.
emit
(
USER_SETTINGS_CHANGED_EVENT_NAME
,
{
"setting"
:
setting_name
,
"old"
:
serialized_old_value
,
"new"
:
serialized_new_value
,
"truncated"
:
truncated_values
,
"user_id"
:
user
.
id
,
"table"
:
db_table
,
}
truncated_fields
)
...
...
common/test/acceptance/tests/lms/test_teams.py
View file @
8c1bf2cd
...
...
@@ -1017,6 +1017,7 @@ class EditTeamTest(TeamFormActions):
Then I should see the Edit Team button
And When I click edit team button
Then I should see the edit team page
And an analytics event should be fired
When I edit all the fields with appropriate data
And I click Update button
Then I should see the page for my team with updated data
...
...
@@ -1030,7 +1031,55 @@ class EditTeamTest(TeamFormActions):
self
.
verify_and_navigate_to_edit_team_page
()
self
.
fill_create_or_edit_form
()
self
.
create_or_edit_team_page
.
submit_form
()
expected_events
=
[
{
'event_type'
:
'edx.team.changed'
,
'event'
:
{
'course_id'
:
self
.
course_id
,
'team_id'
:
self
.
team
[
'id'
],
'field'
:
'country'
,
'old'
:
'AF'
,
'new'
:
'PK'
,
'truncated'
:
[],
}
},
{
'event_type'
:
'edx.team.changed'
,
'event'
:
{
'course_id'
:
self
.
course_id
,
'team_id'
:
self
.
team
[
'id'
],
'field'
:
'name'
,
'old'
:
self
.
team
[
'name'
],
'new'
:
self
.
TEAMS_NAME
,
'truncated'
:
[],
}
},
{
'event_type'
:
'edx.team.changed'
,
'event'
:
{
'course_id'
:
self
.
course_id
,
'team_id'
:
self
.
team
[
'id'
],
'field'
:
'language'
,
'old'
:
'aa'
,
'new'
:
'en'
,
'truncated'
:
[],
}
},
{
'event_type'
:
'edx.team.changed'
,
'event'
:
{
'course_id'
:
self
.
course_id
,
'team_id'
:
self
.
team
[
'id'
],
'field'
:
'description'
,
'old'
:
self
.
team
[
'description'
],
'new'
:
self
.
TEAM_DESCRIPTION
,
'truncated'
:
[],
}
},
]
with
self
.
assert_events_match_during
(
event_filter
=
self
.
only_team_events
,
expected_events
=
expected_events
):
self
.
create_or_edit_team_page
.
submit_form
()
self
.
team_page
.
wait_for_page
()
...
...
lms/djangoapps/teams/models.py
View file @
8c1bf2cd
...
...
@@ -4,6 +4,7 @@ from datetime import datetime
from
uuid
import
uuid4
import
pytz
from
datetime
import
datetime
from
model_utils
import
FieldTracker
from
django.core.exceptions
import
ObjectDoesNotExist
from
django.contrib.auth.models
import
User
...
...
@@ -89,6 +90,11 @@ class CourseTeam(models.Model):
users
=
models
.
ManyToManyField
(
User
,
db_index
=
True
,
related_name
=
'teams'
,
through
=
'CourseTeamMembership'
)
team_size
=
models
.
IntegerField
(
default
=
0
,
db_index
=
True
)
# indexed for ordering
field_tracker
=
FieldTracker
()
# Don't emit changed events when these fields change.
FIELD_BLACKLIST
=
[
'last_activity_at'
,
'team_size'
]
@classmethod
def
create
(
cls
,
name
,
course_id
,
description
,
topic_id
=
None
,
country
=
None
,
language
=
None
):
"""Create a complete CourseTeam object.
...
...
lms/djangoapps/teams/tests/test_views.py
View file @
8c1bf2cd
...
...
@@ -743,9 +743,12 @@ class TestDetailTeamAPI(TeamAPITestCase):
@ddt.ddt
class
TestUpdateTeamAPI
(
TeamAPITestCase
):
class
TestUpdateTeamAPI
(
EventTestMixin
,
TeamAPITestCase
):
"""Test cases for the team update endpoint."""
def
setUp
(
self
):
# pylint: disable=arguments-differ
super
(
TestUpdateTeamAPI
,
self
)
.
setUp
(
'teams.views.tracker'
)
@ddt.data
(
(
None
,
401
),
(
'student_inactive'
,
401
),
...
...
@@ -757,9 +760,19 @@ class TestUpdateTeamAPI(TeamAPITestCase):
)
@ddt.unpack
def
test_access
(
self
,
user
,
status
):
prev_name
=
self
.
solar_team
.
name
team
=
self
.
patch_team_detail
(
self
.
solar_team
.
team_id
,
status
,
{
'name'
:
'foo'
},
user
=
user
)
if
status
==
200
:
self
.
assertEquals
(
team
[
'name'
],
'foo'
)
self
.
assert_event_emitted
(
'edx.team.changed'
,
team_id
=
self
.
solar_team
.
team_id
,
course_id
=
unicode
(
self
.
solar_team
.
course_id
),
truncated
=
[],
field
=
'name'
,
old
=
prev_name
,
new
=
'foo'
)
@ddt.data
(
(
None
,
401
),
...
...
@@ -787,8 +800,22 @@ class TestUpdateTeamAPI(TeamAPITestCase):
@ddt.data
((
'country'
,
'US'
),
(
'language'
,
'en'
),
(
'foo'
,
'bar'
))
@ddt.unpack
def
test_good_requests
(
self
,
key
,
value
):
if
hasattr
(
self
.
solar_team
,
key
):
prev_value
=
getattr
(
self
.
solar_team
,
key
)
self
.
patch_team_detail
(
self
.
solar_team
.
team_id
,
200
,
{
key
:
value
},
user
=
'staff'
)
if
hasattr
(
self
.
solar_team
,
key
):
self
.
assert_event_emitted
(
'edx.team.changed'
,
team_id
=
self
.
solar_team
.
team_id
,
course_id
=
unicode
(
self
.
solar_team
.
course_id
),
truncated
=
[],
field
=
key
,
old
=
prev_value
,
new
=
value
)
def
test_does_not_exist
(
self
):
self
.
patch_team_detail
(
'no_such_team'
,
404
,
user
=
'staff'
)
...
...
lms/djangoapps/teams/views.py
View file @
8c1bf2cd
...
...
@@ -16,6 +16,8 @@ from rest_framework.authentication import (
from
rest_framework
import
status
from
rest_framework
import
permissions
from
django.db.models
import
Count
from
django.db.models.signals
import
post_save
from
django.dispatch
import
receiver
from
django.contrib.auth.models
import
User
from
django_countries
import
countries
from
django.utils.translation
import
ugettext
as
_
...
...
@@ -40,6 +42,7 @@ from student.models import CourseEnrollment, CourseAccessRole
from
student.roles
import
CourseStaffRole
from
django_comment_client.utils
import
has_discussion_privileges
from
teams
import
is_feature_enabled
from
util.model_utils
import
truncate_fields
from
.models
import
CourseTeam
,
CourseTeamMembership
from
.serializers
import
(
CourseTeamSerializer
,
...
...
@@ -59,6 +62,25 @@ TOPICS_PER_PAGE = 12
MAXIMUM_SEARCH_SIZE
=
100000
@receiver
(
post_save
,
sender
=
CourseTeam
)
def
team_post_save_callback
(
sender
,
instance
,
**
kwargs
):
# pylint: disable=unused-argument
""" Emits signal after the team is saved. """
changed_fields
=
instance
.
field_tracker
.
changed
()
# Don't emit events when we are first creating the team.
if
not
kwargs
[
'created'
]:
for
field
in
changed_fields
:
if
field
not
in
instance
.
FIELD_BLACKLIST
:
truncated_fields
=
truncate_fields
(
unicode
(
changed_fields
[
field
]),
unicode
(
getattr
(
instance
,
field
)))
truncated_fields
[
'team_id'
]
=
instance
.
team_id
truncated_fields
[
'course_id'
]
=
unicode
(
instance
.
course_id
)
truncated_fields
[
'field'
]
=
field
tracker
.
emit
(
'edx.team.changed'
,
truncated_fields
)
class
TeamsDashboardView
(
View
):
"""
View methods related to the teams dashboard.
...
...
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