feat: added support for new topics for mobile (#31441)
Co-authored-by: adeel.tajamul <adeel.tajamul@arbisoft.com>
This commit is contained in:
committed by
GitHub
parent
6ef0aba48d
commit
e04d53a9a1
@@ -33,6 +33,7 @@ from common.djangoapps.student.roles import (
|
||||
CourseStaffRole,
|
||||
)
|
||||
|
||||
from lms.djangoapps.course_api.blocks.api import get_blocks
|
||||
from lms.djangoapps.course_blocks.api import get_course_blocks
|
||||
from lms.djangoapps.courseware.courses import get_course_with_access
|
||||
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
|
||||
@@ -116,13 +117,16 @@ from .serializers import (
|
||||
get_context
|
||||
)
|
||||
from .utils import (
|
||||
AttributeDict,
|
||||
add_stats_for_users_with_no_discussion_content,
|
||||
create_blocks_params,
|
||||
discussion_open_for_user,
|
||||
get_usernames_for_course,
|
||||
get_usernames_from_search_string,
|
||||
set_attribute
|
||||
)
|
||||
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
ThreadType = Literal["discussion", "question"]
|
||||
@@ -533,6 +537,108 @@ def get_course_topics(request: Request, course_key: CourseKey, topic_ids: Option
|
||||
}
|
||||
|
||||
|
||||
def get_v2_non_courseware_topics_as_v1(request, course_key, topics):
|
||||
"""
|
||||
Takes v2 topics list and returns v1 list of non courseware topics
|
||||
"""
|
||||
non_courseware_topics = []
|
||||
for topic in topics:
|
||||
if topic.get('usage_key', '') is None:
|
||||
for key in ['usage_key', 'enabled_in_context']:
|
||||
topic.pop(key)
|
||||
topic.update({
|
||||
'children': [],
|
||||
'thread_list_url': get_thread_list_url(
|
||||
request,
|
||||
course_key,
|
||||
topic.get('id'),
|
||||
)
|
||||
})
|
||||
non_courseware_topics.append(topic)
|
||||
return non_courseware_topics
|
||||
|
||||
|
||||
def get_v2_courseware_topics_as_v1(request, course_key, sequentials, topics):
|
||||
"""
|
||||
Returns v2 courseware topics list as v1 structure
|
||||
"""
|
||||
courseware_topics = []
|
||||
for sequential in sequentials:
|
||||
children = []
|
||||
for child in sequential.get('children', []):
|
||||
for topic in topics:
|
||||
if child == topic.get('usage_key'):
|
||||
topic.update({
|
||||
'children': [],
|
||||
'thread_list_url': get_thread_list_url(
|
||||
request,
|
||||
course_key,
|
||||
[topic.get('id')],
|
||||
)
|
||||
})
|
||||
topic.pop('enabled_in_context')
|
||||
children.append(AttributeDict(topic))
|
||||
|
||||
discussion_topic = DiscussionTopic(
|
||||
None,
|
||||
sequential.get('display_name'),
|
||||
get_thread_list_url(
|
||||
request,
|
||||
course_key,
|
||||
[child.id for child in children],
|
||||
),
|
||||
children,
|
||||
None,
|
||||
)
|
||||
courseware_topics.append(DiscussionTopicSerializer(discussion_topic).data)
|
||||
return courseware_topics
|
||||
|
||||
|
||||
def get_v2_course_topics_as_v1(
|
||||
request: Request,
|
||||
course_key: CourseKey,
|
||||
topic_ids: Optional[Iterable[str]] = None,
|
||||
):
|
||||
"""
|
||||
Returns v2 topics in v1 structure
|
||||
"""
|
||||
course_usage_key = modulestore().make_course_usage_key(course_key)
|
||||
blocks_params = create_blocks_params(course_usage_key, request.user)
|
||||
blocks = get_blocks(
|
||||
request,
|
||||
blocks_params['usage_key'],
|
||||
blocks_params['user'],
|
||||
blocks_params['depth'],
|
||||
blocks_params['nav_depth'],
|
||||
blocks_params['requested_fields'],
|
||||
blocks_params['block_counts'],
|
||||
blocks_params['student_view_data'],
|
||||
blocks_params['return_type'],
|
||||
blocks_params['block_types_filter'],
|
||||
hide_access_denials=False,
|
||||
)['blocks']
|
||||
|
||||
sequentials = [value for _, value in blocks.items()
|
||||
if value.get('type') == "sequential"]
|
||||
|
||||
topics = get_course_topics_v2(course_key, request.user, topic_ids)
|
||||
non_courseware_topics = get_v2_non_courseware_topics_as_v1(
|
||||
request,
|
||||
course_key,
|
||||
topics,
|
||||
)
|
||||
courseware_topics = get_v2_courseware_topics_as_v1(
|
||||
request,
|
||||
course_key,
|
||||
sequentials,
|
||||
topics,
|
||||
)
|
||||
return {
|
||||
"courseware_topics": courseware_topics,
|
||||
"non_courseware_topics": non_courseware_topics,
|
||||
}
|
||||
|
||||
|
||||
def get_course_topics_v2(
|
||||
course_key: CourseKey,
|
||||
user: User,
|
||||
|
||||
@@ -876,6 +876,47 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, CommentsServiceMockMixin,
|
||||
}
|
||||
)
|
||||
|
||||
@override_waffle_flag(ENABLE_NEW_STRUCTURE_DISCUSSIONS, True)
|
||||
def test_new_course_structure_response(self):
|
||||
"""
|
||||
Tests whether the new structure is available on old topics API
|
||||
(For mobile compatibility)
|
||||
"""
|
||||
chapter = ItemFactory.create(
|
||||
parent_location=self.course.location,
|
||||
category='chapter',
|
||||
display_name="Week 1",
|
||||
start=datetime(2015, 3, 1, tzinfo=UTC),
|
||||
)
|
||||
sequential = ItemFactory.create(
|
||||
parent_location=chapter.location,
|
||||
category='sequential',
|
||||
display_name="Lesson 1",
|
||||
start=datetime(2015, 3, 1, tzinfo=UTC),
|
||||
)
|
||||
ItemFactory.create(
|
||||
parent_location=sequential.location,
|
||||
category='vertical',
|
||||
display_name='vertical',
|
||||
start=datetime(2015, 4, 1, tzinfo=UTC),
|
||||
)
|
||||
DiscussionsConfiguration.objects.create(
|
||||
context_key=self.course.id,
|
||||
provider_type=Provider.OPEN_EDX
|
||||
)
|
||||
update_discussions_settings_from_course_task(str(self.course.id))
|
||||
response = json.loads(self.client.get(self.url).content.decode())
|
||||
keys = ['children', 'id', 'name', 'thread_counts', 'thread_list_url']
|
||||
assert list(response.keys()) == ['courseware_topics', 'non_courseware_topics']
|
||||
assert len(response['courseware_topics']) == 1
|
||||
courseware_keys = list(response['courseware_topics'][0].keys())
|
||||
courseware_keys.sort()
|
||||
assert courseware_keys == keys
|
||||
assert len(response['non_courseware_topics']) == 1
|
||||
non_courseware_keys = list(response['non_courseware_topics'][0].keys())
|
||||
non_courseware_keys.sort()
|
||||
assert non_courseware_keys == keys
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@mock.patch('lms.djangoapps.discussion.rest_api.api._get_course', mock.Mock())
|
||||
|
||||
@@ -17,6 +17,15 @@ from openedx.core.djangoapps.django_comment_common.models import (
|
||||
)
|
||||
|
||||
|
||||
class AttributeDict(dict):
|
||||
"""
|
||||
Converts Dict Keys into Attributes
|
||||
"""
|
||||
__getattr__ = dict.__getitem__
|
||||
__setattr__ = dict.__setitem__
|
||||
__delattr__ = dict.__delitem__
|
||||
|
||||
|
||||
def discussion_open_for_user(course, user):
|
||||
"""
|
||||
Check if course discussion are open or not for user.
|
||||
|
||||
@@ -28,6 +28,8 @@ from lms.djangoapps.course_goals.models import UserActivity
|
||||
from lms.djangoapps.discussion.django_comment_client import settings as cc_settings
|
||||
from lms.djangoapps.discussion.django_comment_client.utils import get_group_id_for_comments_service
|
||||
from lms.djangoapps.instructor.access import update_forum_role
|
||||
from openedx.core.djangoapps.discussions.config.waffle import ENABLE_NEW_STRUCTURE_DISCUSSIONS
|
||||
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration, Provider
|
||||
from openedx.core.djangoapps.discussions.serializers import DiscussionSettingsSerializer
|
||||
from openedx.core.djangoapps.django_comment_common import comment_client
|
||||
from openedx.core.djangoapps.django_comment_common.models import CourseDiscussionSettings, Role
|
||||
@@ -52,6 +54,7 @@ from ..rest_api.api import (
|
||||
get_thread_list,
|
||||
get_learner_active_thread_list,
|
||||
get_user_comments,
|
||||
get_v2_course_topics_as_v1,
|
||||
update_comment,
|
||||
update_thread,
|
||||
)
|
||||
@@ -227,11 +230,22 @@ class CourseTopicsView(DeveloperErrorViewMixin, APIView):
|
||||
topic_ids = self.request.GET.get('topic_id')
|
||||
topic_ids = set(topic_ids.strip(',').split(',')) if topic_ids else None
|
||||
with modulestore().bulk_operations(course_key):
|
||||
response = get_course_topics(
|
||||
request,
|
||||
course_key,
|
||||
topic_ids,
|
||||
)
|
||||
configuration = DiscussionsConfiguration.get(context_key=course_key)
|
||||
provider = configuration.provider_type
|
||||
# This will be removed when mobile app will support new topic structure
|
||||
new_structure_enabled = ENABLE_NEW_STRUCTURE_DISCUSSIONS.is_enabled(course_key)
|
||||
if provider == Provider.OPEN_EDX and new_structure_enabled:
|
||||
response = get_v2_course_topics_as_v1(
|
||||
request,
|
||||
course_key,
|
||||
topic_ids
|
||||
)
|
||||
else:
|
||||
response = get_course_topics(
|
||||
request,
|
||||
course_key,
|
||||
topic_ids,
|
||||
)
|
||||
# Record user activity for tracking progress towards a user's course goals (for mobile app)
|
||||
UserActivity.record_user_activity(request.user, course_key, request=request, only_if_mobile_app=True)
|
||||
return Response(response)
|
||||
|
||||
Reference in New Issue
Block a user