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
cf5d276a
Commit
cf5d276a
authored
Aug 24, 2015
by
Sven Marnach
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Emit events when users vote on forum posts.
parent
3f76da0b
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
104 additions
and
119 deletions
+104
-119
lms/djangoapps/discussion_api/api.py
+3
-21
lms/djangoapps/django_comment_client/base/views.py
+101
-98
No files found.
lms/djangoapps/discussion_api/api.py
View file @
cf5d276a
...
@@ -25,13 +25,7 @@ from discussion_api.permissions import (
...
@@ -25,13 +25,7 @@ from discussion_api.permissions import (
get_initializable_thread_fields
,
get_initializable_thread_fields
,
)
)
from
discussion_api.serializers
import
CommentSerializer
,
ThreadSerializer
,
get_context
from
discussion_api.serializers
import
CommentSerializer
,
ThreadSerializer
,
get_context
from
django_comment_client.base.views
import
(
from
django_comment_client.base.views
import
track_comment_created_event
,
track_thread_created_event
THREAD_CREATED_EVENT_NAME
,
get_comment_created_event_data
,
get_comment_created_event_name
,
get_thread_created_event_data
,
track_forum_event
,
)
from
django_comment_common.signals
import
(
from
django_comment_common.signals
import
(
thread_created
,
thread_created
,
thread_edited
,
thread_edited
,
...
@@ -566,13 +560,7 @@ def create_thread(request, thread_data):
...
@@ -566,13 +560,7 @@ def create_thread(request, thread_data):
api_thread
=
serializer
.
data
api_thread
=
serializer
.
data
_do_extra_actions
(
api_thread
,
cc_thread
,
thread_data
.
keys
(),
actions_form
,
context
)
_do_extra_actions
(
api_thread
,
cc_thread
,
thread_data
.
keys
(),
actions_form
,
context
)
track_forum_event
(
track_thread_created_event
(
request
,
course
,
cc_thread
,
actions_form
.
cleaned_data
[
"following"
])
request
,
THREAD_CREATED_EVENT_NAME
,
course
,
cc_thread
,
get_thread_created_event_data
(
cc_thread
,
followed
=
actions_form
.
cleaned_data
[
"following"
])
)
return
api_thread
return
api_thread
...
@@ -616,13 +604,7 @@ def create_comment(request, comment_data):
...
@@ -616,13 +604,7 @@ def create_comment(request, comment_data):
api_comment
=
serializer
.
data
api_comment
=
serializer
.
data
_do_extra_actions
(
api_comment
,
cc_comment
,
comment_data
.
keys
(),
actions_form
,
context
)
_do_extra_actions
(
api_comment
,
cc_comment
,
comment_data
.
keys
(),
actions_form
,
context
)
track_forum_event
(
track_comment_created_event
(
request
,
context
[
"course"
],
cc_comment
,
cc_thread
[
"commentable_id"
],
followed
=
False
)
request
,
get_comment_created_event_name
(
cc_comment
),
context
[
"course"
],
cc_comment
,
get_comment_created_event_data
(
cc_comment
,
cc_thread
[
"commentable_id"
],
followed
=
False
)
)
return
api_comment
return
api_comment
...
...
lms/djangoapps/django_comment_client/base/views.py
View file @
cf5d276a
...
@@ -49,40 +49,7 @@ import lms.lib.comment_client as cc
...
@@ -49,40 +49,7 @@ import lms.lib.comment_client as cc
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
TRACKING_MAX_FORUM_BODY
=
2000
TRACKING_MAX_FORUM_BODY
=
2000
_EVENT_NAME_TEMPLATE
=
'edx.forum.{obj_type}.{action_name}'
THREAD_CREATED_EVENT_NAME
=
"edx.forum.thread.created"
RESPONSE_CREATED_EVENT_NAME
=
'edx.forum.response.created'
COMMENT_CREATED_EVENT_NAME
=
'edx.forum.comment.created'
def
permitted
(
fn
):
@functools.wraps
(
fn
)
def
wrapper
(
request
,
*
args
,
**
kwargs
):
def
fetch_content
():
if
"thread_id"
in
kwargs
:
content
=
cc
.
Thread
.
find
(
kwargs
[
"thread_id"
])
.
to_dict
()
elif
"comment_id"
in
kwargs
:
content
=
cc
.
Comment
.
find
(
kwargs
[
"comment_id"
])
.
to_dict
()
elif
"commentable_id"
in
kwargs
:
content
=
cc
.
Commentable
.
find
(
kwargs
[
"commentable_id"
])
.
to_dict
()
else
:
content
=
None
return
content
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
kwargs
[
'course_id'
])
if
check_permissions_by_view
(
request
.
user
,
course_key
,
fetch_content
(),
request
.
view_name
):
return
fn
(
request
,
*
args
,
**
kwargs
)
else
:
return
JsonError
(
"unauthorized"
,
status
=
401
)
return
wrapper
def
ajax_content_response
(
request
,
course_key
,
content
):
user_info
=
cc
.
User
.
from_django_user
(
request
.
user
)
.
to_dict
()
annotated_content_info
=
get_annotated_content_info
(
course_key
,
content
,
request
.
user
,
user_info
)
return
JsonResponse
({
'content'
:
prepare_content
(
content
,
course_key
),
'annotated_content_info'
:
annotated_content_info
,
})
def
track_forum_event
(
request
,
event_name
,
course
,
obj
,
data
,
id_map
=
None
):
def
track_forum_event
(
request
,
event_name
,
course
,
obj
,
data
,
id_map
=
None
):
...
@@ -100,16 +67,9 @@ def track_forum_event(request, event_name, course, obj, data, id_map=None):
...
@@ -100,16 +67,9 @@ def track_forum_event(request, event_name, course, obj, data, id_map=None):
if
id_map
is
None
:
if
id_map
is
None
:
id_map
=
get_cached_discussion_id_map
(
course
,
[
commentable_id
],
user
)
id_map
=
get_cached_discussion_id_map
(
course
,
[
commentable_id
],
user
)
if
commentable_id
in
id_map
:
if
commentable_id
in
id_map
:
data
[
'category_name'
]
=
id_map
[
commentable_id
][
"title"
]
data
[
'category_name'
]
=
id_map
[
commentable_id
][
"title"
]
data
[
'category_id'
]
=
commentable_id
data
[
'category_id'
]
=
commentable_id
if
len
(
obj
.
body
)
>
TRACKING_MAX_FORUM_BODY
:
data
[
'truncated'
]
=
True
else
:
data
[
'truncated'
]
=
False
data
[
'body'
]
=
obj
.
body
[:
TRACKING_MAX_FORUM_BODY
]
data
[
'url'
]
=
request
.
META
.
get
(
'HTTP_REFERER'
,
''
)
data
[
'url'
]
=
request
.
META
.
get
(
'HTTP_REFERER'
,
''
)
data
[
'user_forums_roles'
]
=
[
data
[
'user_forums_roles'
]
=
[
role
.
name
for
role
in
user
.
roles
.
filter
(
course_id
=
course
.
id
)
role
.
name
for
role
in
user
.
roles
.
filter
(
course_id
=
course
.
id
)
...
@@ -121,12 +81,18 @@ def track_forum_event(request, event_name, course, obj, data, id_map=None):
...
@@ -121,12 +81,18 @@ def track_forum_event(request, event_name, course, obj, data, id_map=None):
tracker
.
emit
(
event_name
,
data
)
tracker
.
emit
(
event_name
,
data
)
def
get_thread_created_event_data
(
thread
,
followed
):
def
track_created_event
(
request
,
event_name
,
course
,
obj
,
data
):
"""
if
len
(
obj
.
body
)
>
TRACKING_MAX_FORUM_BODY
:
Get the event data payload for thread creation (excluding fields populated
data
[
'truncated'
]
=
True
by track_forum_event)
else
:
"""
data
[
'truncated'
]
=
False
return
{
data
[
'body'
]
=
obj
.
body
[:
TRACKING_MAX_FORUM_BODY
]
track_forum_event
(
request
,
event_name
,
course
,
obj
,
data
)
def
track_thread_created_event
(
request
,
course
,
thread
,
followed
):
event_name
=
_EVENT_NAME_TEMPLATE
.
format
(
obj_type
=
'thread'
,
action_name
=
'created'
)
event_data
=
{
'commentable_id'
:
thread
.
commentable_id
,
'commentable_id'
:
thread
.
commentable_id
,
'group_id'
:
thread
.
get
(
"group_id"
),
'group_id'
:
thread
.
get
(
"group_id"
),
'thread_type'
:
thread
.
thread_type
,
'thread_type'
:
thread
.
thread_type
,
...
@@ -139,29 +105,66 @@ def get_thread_created_event_data(thread, followed):
...
@@ -139,29 +105,66 @@ def get_thread_created_event_data(thread, followed):
# However, the view does not contain that data, and including it will
# However, the view does not contain that data, and including it will
# likely require changes elsewhere.
# likely require changes elsewhere.
}
}
track_created_event
(
request
,
event_name
,
course
,
thread
,
event_data
)
def
get_comment_created_event_name
(
comment
):
def
track_comment_created_event
(
request
,
course
,
comment
,
commentable_id
,
followed
):
"""Get the appropriate event name for creating a response/comment"""
obj_type
=
'comment'
if
comment
.
get
(
"parent_id"
)
else
'response'
return
COMMENT_CREATED_EVENT_NAME
if
comment
.
get
(
"parent_id"
)
else
RESPONSE_CREATED_EVENT_NAME
event_name
=
_EVENT_NAME_TEMPLATE
.
format
(
obj_type
=
obj_type
,
action_name
=
'created'
)
def
get_comment_created_event_data
(
comment
,
commentable_id
,
followed
):
"""
Get the event data payload for comment creation (excluding fields populated
by track_forum_event)
"""
event_data
=
{
event_data
=
{
'discussion'
:
{
'id'
:
comment
.
thread_id
},
'discussion'
:
{
'id'
:
comment
.
thread_id
},
'commentable_id'
:
commentable_id
,
'commentable_id'
:
commentable_id
,
'options'
:
{
'followed'
:
followed
},
'options'
:
{
'followed'
:
followed
},
}
}
parent_id
=
comment
.
get
(
'parent_id'
)
parent_id
=
comment
.
get
(
"parent_id"
)
if
parent_id
:
if
parent_id
:
event_data
[
'response'
]
=
{
'id'
:
parent_id
}
event_data
[
'response'
]
=
{
'id'
:
parent_id
}
track_created_event
(
request
,
event_name
,
course
,
comment
,
event_data
)
def
track_voted_event
(
request
,
course
,
obj
,
vote_value
,
undo_vote
=
False
):
if
isinstance
(
obj
,
cc
.
Thread
):
obj_type
=
'thread'
else
:
obj_type
=
'response'
event_name
=
_EVENT_NAME_TEMPLATE
.
format
(
obj_type
=
obj_type
,
action_name
=
'voted'
)
event_data
=
{
'commentable_id'
:
obj
.
commentable_id
,
'target_username'
:
obj
.
get
(
'username'
),
'undo_vote'
:
undo_vote
,
'vote_value'
:
vote_value
,
}
track_forum_event
(
request
,
event_name
,
course
,
obj
,
event_data
)
def
permitted
(
fn
):
@functools.wraps
(
fn
)
def
wrapper
(
request
,
*
args
,
**
kwargs
):
def
fetch_content
():
if
"thread_id"
in
kwargs
:
content
=
cc
.
Thread
.
find
(
kwargs
[
"thread_id"
])
.
to_dict
()
elif
"comment_id"
in
kwargs
:
content
=
cc
.
Comment
.
find
(
kwargs
[
"comment_id"
])
.
to_dict
()
elif
"commentable_id"
in
kwargs
:
content
=
cc
.
Commentable
.
find
(
kwargs
[
"commentable_id"
])
.
to_dict
()
else
:
content
=
None
return
content
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
kwargs
[
'course_id'
])
if
check_permissions_by_view
(
request
.
user
,
course_key
,
fetch_content
(),
request
.
view_name
):
return
fn
(
request
,
*
args
,
**
kwargs
)
else
:
return
JsonError
(
"unauthorized"
,
status
=
401
)
return
wrapper
return
event_data
def
ajax_content_response
(
request
,
course_key
,
content
):
user_info
=
cc
.
User
.
from_django_user
(
request
.
user
)
.
to_dict
()
annotated_content_info
=
get_annotated_content_info
(
course_key
,
content
,
request
.
user
,
user_info
)
return
JsonResponse
({
'content'
:
prepare_content
(
content
,
course_key
),
'annotated_content_info'
:
annotated_content_info
,
})
@require_POST
@require_POST
...
@@ -234,12 +237,11 @@ def create_thread(request, course_id, commentable_id):
...
@@ -234,12 +237,11 @@ def create_thread(request, course_id, commentable_id):
cc_user
=
cc
.
User
.
from_django_user
(
user
)
cc_user
=
cc
.
User
.
from_django_user
(
user
)
cc_user
.
follow
(
thread
)
cc_user
.
follow
(
thread
)
event_data
=
get_thread_created_event_data
(
thread
,
follow
)
data
=
thread
.
to_dict
()
data
=
thread
.
to_dict
()
add_courseware_context
([
data
],
course
,
user
)
add_courseware_context
([
data
],
course
,
user
)
track_
forum_event
(
request
,
THREAD_CREATED_EVENT_NAME
,
course
,
thread
,
event_data
)
track_
thread_created_event
(
request
,
course
,
thread
,
follow
)
if
request
.
is_ajax
():
if
request
.
is_ajax
():
return
ajax_content_response
(
request
,
course_key
,
data
)
return
ajax_content_response
(
request
,
course_key
,
data
)
...
@@ -330,9 +332,7 @@ def _create_comment(request, course_key, thread_id=None, parent_id=None):
...
@@ -330,9 +332,7 @@ def _create_comment(request, course_key, thread_id=None, parent_id=None):
cc_user
=
cc
.
User
.
from_django_user
(
request
.
user
)
cc_user
=
cc
.
User
.
from_django_user
(
request
.
user
)
cc_user
.
follow
(
comment
.
thread
)
cc_user
.
follow
(
comment
.
thread
)
event_name
=
get_comment_created_event_name
(
comment
)
track_comment_created_event
(
request
,
course
,
comment
,
comment
.
thread
.
commentable_id
,
followed
)
event_data
=
get_comment_created_event_data
(
comment
,
comment
.
thread
.
commentable_id
,
followed
)
track_forum_event
(
request
,
event_name
,
course
,
comment
,
event_data
)
if
request
.
is_ajax
():
if
request
.
is_ajax
():
return
ajax_content_response
(
request
,
course_key
,
comment
.
to_dict
())
return
ajax_content_response
(
request
,
course_key
,
comment
.
to_dict
())
...
@@ -456,6 +456,24 @@ def delete_comment(request, course_id, comment_id):
...
@@ -456,6 +456,24 @@ def delete_comment(request, course_id, comment_id):
return
JsonResponse
(
prepare_content
(
comment
.
to_dict
(),
course_key
))
return
JsonResponse
(
prepare_content
(
comment
.
to_dict
(),
course_key
))
def
_vote_or_unvote
(
request
,
course_id
,
obj
,
value
=
'up'
,
undo_vote
=
False
):
"""
Vote or unvote for a thread or a response.
"""
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
course
=
get_course_with_access
(
request
.
user
,
'load'
,
course_key
)
user
=
cc
.
User
.
from_django_user
(
request
.
user
)
if
undo_vote
:
user
.
unvote
(
obj
)
# TODO(smarnach): Determine the value of the vote that is undone. Currently, you can
# only cast upvotes in the user interface, so it is assumed that the vote value is 'up'.
# (People could theoretically downvote by handcrafting AJAX requests.)
else
:
user
.
vote
(
obj
,
value
)
track_voted_event
(
request
,
course
,
obj
,
value
,
undo_vote
)
return
JsonResponse
(
prepare_content
(
obj
.
to_dict
(),
course_key
))
@require_POST
@require_POST
@login_required
@login_required
@permitted
@permitted
...
@@ -463,13 +481,10 @@ def vote_for_comment(request, course_id, comment_id, value):
...
@@ -463,13 +481,10 @@ def vote_for_comment(request, course_id, comment_id, value):
"""
"""
given a course_id and comment_id,
given a course_id and comment_id,
"""
"""
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
user
=
request
.
user
cc_user
=
cc
.
User
.
from_django_user
(
user
)
comment
=
cc
.
Comment
.
find
(
comment_id
)
comment
=
cc
.
Comment
.
find
(
comment_id
)
cc_user
.
vote
(
comment
,
value
)
result
=
_vote_or_unvote
(
request
,
course_id
,
comment
,
value
)
comment_voted
.
send
(
sender
=
None
,
user
=
user
,
post
=
comment
)
comment_voted
.
send
(
sender
=
None
,
user
=
request
.
user
,
post
=
comment
)
return
JsonResponse
(
prepare_content
(
comment
.
to_dict
(),
course_key
))
return
result
@require_POST
@require_POST
...
@@ -480,11 +495,7 @@ def undo_vote_for_comment(request, course_id, comment_id):
...
@@ -480,11 +495,7 @@ def undo_vote_for_comment(request, course_id, comment_id):
given a course id and comment id, remove vote
given a course id and comment id, remove vote
ajax only
ajax only
"""
"""
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
return
_vote_or_unvote
(
request
,
course_id
,
cc
.
Comment
.
find
(
comment_id
),
undo_vote
=
True
)
user
=
cc
.
User
.
from_django_user
(
request
.
user
)
comment
=
cc
.
Comment
.
find
(
comment_id
)
user
.
unvote
(
comment
)
return
JsonResponse
(
prepare_content
(
comment
.
to_dict
(),
course_key
))
@require_POST
@require_POST
...
@@ -495,13 +506,21 @@ def vote_for_thread(request, course_id, thread_id, value):
...
@@ -495,13 +506,21 @@ def vote_for_thread(request, course_id, thread_id, value):
given a course id and thread id vote for this thread
given a course id and thread id vote for this thread
ajax only
ajax only
"""
"""
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
user
=
request
.
user
cc_user
=
cc
.
User
.
from_django_user
(
user
)
thread
=
cc
.
Thread
.
find
(
thread_id
)
thread
=
cc
.
Thread
.
find
(
thread_id
)
cc_user
.
vote
(
thread
,
value
)
result
=
_vote_or_unvote
(
request
,
course_id
,
thread
,
value
)
thread_voted
.
send
(
sender
=
None
,
user
=
user
,
post
=
thread
)
thread_voted
.
send
(
sender
=
None
,
user
=
request
.
user
,
post
=
thread
)
return
JsonResponse
(
prepare_content
(
thread
.
to_dict
(),
course_key
))
return
result
@require_POST
@login_required
@permitted
def
undo_vote_for_thread
(
request
,
course_id
,
thread_id
):
"""
given a course id and thread id, remove users vote for thread
ajax only
"""
return
_vote_or_unvote
(
request
,
course_id
,
cc
.
Thread
.
find
(
thread_id
),
undo_vote
=
True
)
@require_POST
@require_POST
...
@@ -579,22 +598,6 @@ def un_flag_abuse_for_comment(request, course_id, comment_id):
...
@@ -579,22 +598,6 @@ def un_flag_abuse_for_comment(request, course_id, comment_id):
@require_POST
@require_POST
@login_required
@login_required
@permitted
@permitted
def
undo_vote_for_thread
(
request
,
course_id
,
thread_id
):
"""
given a course id and thread id, remove users vote for thread
ajax only
"""
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
user
=
cc
.
User
.
from_django_user
(
request
.
user
)
thread
=
cc
.
Thread
.
find
(
thread_id
)
user
.
unvote
(
thread
)
return
JsonResponse
(
prepare_content
(
thread
.
to_dict
(),
course_key
))
@require_POST
@login_required
@permitted
def
pin_thread
(
request
,
course_id
,
thread_id
):
def
pin_thread
(
request
,
course_id
,
thread_id
):
"""
"""
given a course id and thread id, pin this thread
given a course id and thread id, pin this thread
...
...
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