Commit 01c22531 by cahrens

Add team permission check on commentable_id.

TNL-2864
parent 7a32fbc9
......@@ -51,6 +51,8 @@ def permitted(fn):
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
......@@ -608,16 +610,6 @@ def follow_commentable(request, course_id, commentable_id):
@require_POST
@login_required
@permitted
def follow_user(request, course_id, followed_user_id):
user = cc.User.from_django_user(request.user)
followed_user = cc.User.find(followed_user_id)
user.follow(followed_user)
return JsonResponse({})
@require_POST
@login_required
@permitted
def unfollow_thread(request, course_id, thread_id):
"""
given a course id and thread id, stop following this thread
......@@ -645,20 +637,6 @@ def unfollow_commentable(request, course_id, commentable_id):
@require_POST
@login_required
@permitted
def unfollow_user(request, course_id, followed_user_id):
"""
given a course id and user id, stop following this user
ajax only
"""
user = cc.User.from_django_user(request.user)
followed_user = cc.User.find(followed_user_id)
user.unfollow(followed_user)
return JsonResponse({})
@require_POST
@login_required
@csrf.csrf_exempt
def upload(request, course_id): # ajax upload file to a question or answer
"""view that handles file upload via Ajax
......
......@@ -333,11 +333,11 @@ class SingleThreadQueryCountTestCase(ModuleStoreTestCase):
@ddt.data(
# old mongo with cache
(ModuleStoreEnum.Type.mongo, 1, 7, 5, 13, 8),
(ModuleStoreEnum.Type.mongo, 50, 7, 5, 13, 8),
(ModuleStoreEnum.Type.mongo, 1, 7, 5, 14, 8),
(ModuleStoreEnum.Type.mongo, 50, 7, 5, 14, 8),
# split mongo: 3 queries, regardless of thread response size.
(ModuleStoreEnum.Type.split, 1, 3, 3, 13, 8),
(ModuleStoreEnum.Type.split, 50, 3, 3, 13, 8),
(ModuleStoreEnum.Type.split, 1, 3, 3, 14, 8),
(ModuleStoreEnum.Type.split, 50, 3, 3, 14, 8),
)
@ddt.unpack
def test_number_of_mongo_queries(
......
......@@ -10,6 +10,7 @@ from lms.lib.comment_client import Thread
from opaque_keys.edx.keys import CourseKey
from django_comment_common.models import all_permissions_for_user_in_course
from teams.models import CourseTeam
def has_permission(user, permission, course_id=None):
......@@ -27,7 +28,7 @@ def has_permission(user, permission, course_id=None):
return permission in all_permissions
CONDITIONS = ['is_open', 'is_author', 'is_question_author']
CONDITIONS = ['is_open', 'is_author', 'is_question_author', 'is_team_member_if_applicable']
def _check_condition(user, condition, content):
......@@ -55,10 +56,37 @@ def _check_condition(user, condition, content):
except KeyError:
return False
def check_team_member(user, content):
"""
If the content has a commentable_id, verifies that either it is not associated with a team,
or if it is, that the user is a member of that team.
"""
if not content:
return False
try:
commentable_id = content['commentable_id']
request_cache_dict = RequestCache.get_request_cache().data
cache_key = "django_comment_client.check_team_member.{}.{}".format(user.id, commentable_id)
if cache_key in request_cache_dict:
return request_cache_dict[cache_key]
team = CourseTeam.objects.get(discussion_topic_id=commentable_id)
passes_condition = team.users.filter(id=user.id).count() > 0
request_cache_dict[cache_key] = passes_condition
except KeyError:
# We do not expect KeyError in production-- it usually indicates an improper test mock.
logging.warning("Did not find key commentable_id in content.")
passes_condition = False
except CourseTeam.DoesNotExist:
passes_condition = True
request_cache_dict[cache_key] = passes_condition
return passes_condition
handlers = {
'is_open': check_open,
'is_author': check_author,
'is_question_author': check_question_author,
'is_team_member_if_applicable': check_team_member
}
return handlers[condition](user, content)
......@@ -88,30 +116,28 @@ def _check_conditions_permissions(user, permissions, course_id, content):
VIEW_PERMISSIONS = {
'update_thread': ['edit_content', ['update_thread', 'is_open', 'is_author']],
'create_comment': [["create_comment", "is_open"]],
'create_comment': [["create_comment", "is_open", "is_team_member_if_applicable"]],
'delete_thread': ['delete_thread', ['update_thread', 'is_author']],
'update_comment': ['edit_content', ['update_comment', 'is_open', 'is_author']],
'endorse_comment': ['endorse_comment', 'is_question_author'],
'openclose_thread': ['openclose_thread'],
'create_sub_comment': [['create_sub_comment', 'is_open']],
'create_sub_comment': [['create_sub_comment', 'is_open', 'is_team_member_if_applicable']],
'delete_comment': ['delete_comment', ['update_comment', 'is_open', 'is_author']],
'vote_for_comment': [['vote', 'is_open']],
'undo_vote_for_comment': [['unvote', 'is_open']],
'vote_for_thread': [['vote', 'is_open']],
'flag_abuse_for_thread': ['vote'],
'un_flag_abuse_for_thread': ['vote'],
'flag_abuse_for_comment': ['vote'],
'un_flag_abuse_for_comment': ['vote'],
'undo_vote_for_thread': [['unvote', 'is_open']],
'vote_for_comment': [['vote', 'is_open', 'is_team_member_if_applicable']],
'undo_vote_for_comment': [['unvote', 'is_open', 'is_team_member_if_applicable']],
'vote_for_thread': [['vote', 'is_open', 'is_team_member_if_applicable']],
'flag_abuse_for_thread': [['vote', 'is_team_member_if_applicable']],
'un_flag_abuse_for_thread': [['vote', 'is_team_member_if_applicable']],
'flag_abuse_for_comment': [['vote', 'is_team_member_if_applicable']],
'un_flag_abuse_for_comment': [['vote', 'is_team_member_if_applicable']],
'undo_vote_for_thread': [['unvote', 'is_open', 'is_team_member_if_applicable']],
'pin_thread': ['openclose_thread'],
'un_pin_thread': ['openclose_thread'],
'follow_thread': ['follow_thread'],
'follow_commentable': ['follow_commentable'],
'follow_user': ['follow_user'],
'unfollow_thread': ['unfollow_thread'],
'unfollow_commentable': ['unfollow_commentable'],
'unfollow_user': ['unfollow_user'],
'create_thread': ['create_thread'],
'follow_thread': [['follow_thread', 'is_team_member_if_applicable']],
'follow_commentable': [['follow_commentable', 'is_team_member_if_applicable']],
'unfollow_thread': [['unfollow_thread', 'is_team_member_if_applicable']],
'unfollow_commentable': [['unfollow_commentable', 'is_team_member_if_applicable']],
'create_thread': [['create_thread', 'is_team_member_if_applicable']],
}
......
......@@ -5,5 +5,15 @@ from lms.lib.comment_client import settings
class Commentable(models.Model):
accessible_fields = ['id', 'commentable_id']
base_url = "{prefix}/commentables".format(prefix=settings.PREFIX)
type = 'commentable'
def retrieve(self, *args, **kwargs):
"""
Override default behavior because commentables don't actually exist in the comment service.
"""
self.attributes["commentable_id"] = self.attributes["id"]
self.retrieved = True
return self
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment