Discussion consolidation: quality

This commit is contained in:
Nimisha Asthagiri
2019-04-29 02:44:44 -04:00
parent 97862d2ed7
commit c2e232a3d4
41 changed files with 140 additions and 74 deletions

View File

@@ -10,7 +10,7 @@ from courseware.access import has_access
from courseware.tests.factories import BetaTesterFactory
from lms.djangoapps.ccx.tests.test_overrides import inject_field_overrides
from lms.djangoapps.courseware.field_overrides import OverrideFieldData, OverrideModulestoreFieldData
from lms.djangoapps.django_comment_client.utils import get_accessible_discussion_xblocks
from lms.djangoapps.discussion.django_comment_client.utils import get_accessible_discussion_xblocks
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory

View File

@@ -1,2 +1,3 @@
# pylint: disable=missing-docstring,relative-import
# This import registers the ForumThreadViewedEventTransformer
import event_transformers # pylint: disable=relative-import
import event_transformers

View File

@@ -1,3 +1,4 @@
# pylint: skip-file
"""
Transformers for Discussion-related events.
"""

View File

@@ -1,3 +1,4 @@
# pylint: skip-file
# -*- coding: utf-8 -*-
"""Tests for django comment client views."""
import json

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring,unused-argument
"""Views for discussion forums."""
from __future__ import print_function
@@ -20,24 +21,7 @@ from django.views.decorators.http import require_GET, require_POST
from opaque_keys.edx.keys import CourseKey
from six import text_type
import lms.djangoapps.discussion.django_comment_client.settings as cc_settings
import django_comment_common.comment_client as cc
from courseware.access import has_access
from courseware.courses import get_course_by_id, get_course_overview_with_access, get_course_with_access
from lms.djangoapps.discussion.django_comment_client.permissions import check_permissions_by_view, get_team, has_permission
from lms.djangoapps.discussion.django_comment_client.utils import (
JsonError,
JsonResponse,
add_courseware_context,
discussion_category_id_access,
get_ability,
get_annotated_content_info,
get_cached_discussion_id_map,
get_group_id_for_comments_service,
get_user_group_ids,
is_comment_too_deep,
prepare_content
)
from django_comment_common.signals import (
comment_created,
comment_deleted,
@@ -52,8 +36,27 @@ from django_comment_common.signals import (
thread_unfollowed,
)
from django_comment_common.utils import ThreadContext
import eventtracking
from courseware.access import has_access
from courseware.courses import get_course_by_id, get_course_overview_with_access, get_course_with_access
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
from lms.djangoapps.discussion.django_comment_client.permissions import (
check_permissions_by_view, get_team, has_permission,
)
import lms.djangoapps.discussion.django_comment_client.settings as cc_settings
from lms.djangoapps.discussion.django_comment_client.utils import (
JsonError,
JsonResponse,
add_courseware_context,
discussion_category_id_access,
get_ability,
get_annotated_content_info,
get_cached_discussion_id_map,
get_group_id_for_comments_service,
get_user_group_ids,
is_comment_too_deep,
prepare_content
)
import eventtracking
from util.file import store_uploaded_file
log = logging.getLogger(__name__)
@@ -96,10 +99,7 @@ def track_created_event(request, event_name, course, obj, data):
"""
Send analytics event for a newly created thread, response or comment.
"""
if len(obj.body) > TRACKING_MAX_FORUM_BODY:
data['truncated'] = True
else:
data['truncated'] = False
data['truncated'] = bool(len(obj.body) > TRACKING_MAX_FORUM_BODY)
data['body'] = obj.body[:TRACKING_MAX_FORUM_BODY]
track_forum_event(request, event_name, course, obj, data)

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
import json
import logging

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
"""
Module for checking permissions with the comment_client backend
"""

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
from django.conf import settings
MAX_COMMENT_DEPTH = None
@@ -7,4 +8,7 @@ ALLOWED_UPLOAD_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff')
if hasattr(settings, 'DISCUSSION_SETTINGS'):
MAX_COMMENT_DEPTH = settings.DISCUSSION_SETTINGS.get('MAX_COMMENT_DEPTH')
MAX_UPLOAD_FILE_SIZE = settings.DISCUSSION_SETTINGS.get('MAX_UPLOAD_FILE_SIZE') or MAX_UPLOAD_FILE_SIZE
ALLOWED_UPLOAD_FILE_TYPES = settings.DISCUSSION_SETTINGS.get('ALLOWED_UPLOAD_FILE_TYPES') or ALLOWED_UPLOAD_FILE_TYPES
ALLOWED_UPLOAD_FILE_TYPES = (
settings.DISCUSSION_SETTINGS.get('ALLOWED_UPLOAD_FILE_TYPES') or
ALLOWED_UPLOAD_FILE_TYPES
)

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
from factory.django import DjangoModelFactory
from django_comment_common.models import Permission, Role

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
import json
import re

View File

@@ -1,3 +1,4 @@
# pylint: skip-file
import json
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from logging import getLogger

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
import json
import threading
import unittest

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
import json
import django.http

View File

@@ -1,3 +1,4 @@
# pylint: skip-file
# -*- coding: utf-8 -*-
import datetime
import json
@@ -12,15 +13,10 @@ from mock import Mock, patch
from pytz import UTC
from six import text_type
import lms.djangoapps.discussion.django_comment_client.utils as utils
from course_modes.models import CourseMode
from course_modes.tests.factories import CourseModeFactory
from courseware.tabs import get_course_tab_list
from courseware.tests.factories import InstructorFactory
from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY, TYPE_SUBCATEGORY
from lms.djangoapps.discussion.django_comment_client.tests.factories import RoleFactory
from lms.djangoapps.discussion.django_comment_client.tests.unicode import UnicodeTestMixin
from lms.djangoapps.discussion.django_comment_client.tests.utils import config_course_discussions, topic_name_to_id
from django_comment_common.comment_client.utils import CommentClientMaintenanceError, perform_request
from django_comment_common.models import (
CourseDiscussionSettings,
@@ -33,6 +29,11 @@ from django_comment_common.utils import (
seed_permissions_roles,
set_course_discussion_settings
)
from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY, TYPE_SUBCATEGORY
from lms.djangoapps.discussion.django_comment_client.tests.factories import RoleFactory
from lms.djangoapps.discussion.django_comment_client.tests.unicode import UnicodeTestMixin
from lms.djangoapps.discussion.django_comment_client.tests.utils import config_course_discussions, topic_name_to_id
import lms.djangoapps.discussion.django_comment_client.utils as utils
from lms.djangoapps.teams.tests.factories import CourseTeamFactory
from openedx.core.djangoapps.course_groups import cohorts
from openedx.core.djangoapps.course_groups.cohorts import set_course_cohorted

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
# coding=utf-8
@@ -15,7 +16,9 @@ class UnicodeTestMixin(object):
self._test_unicode_data(u"𝕋𝕙𝕚𝕤 𝕡𝕠𝕤𝕥 𝕔𝕠𝕟𝕥𝕒𝕚𝕟𝕤 𝕔𝕙𝕒𝕣𝕒𝕔𝕥𝕖𝕣𝕤 𝕠𝕦𝕥𝕤𝕚𝕕𝕖 𝕥𝕙𝕖 𝔹𝕄")
def test_special_chars(self):
self._test_unicode_data(u"\" This , post > contains < delimiter ] and [ other } special { characters ; that & may ' break things")
self._test_unicode_data(
u"\" This , post > contains < delimiter ] and [ other } special { characters ; that & may ' break things"
)
def test_string_interp(self):
self._test_unicode_data(u"This post contains %s string interpolation #{syntax}")

View File

@@ -1,3 +1,4 @@
# pylint: skip-file
import json
import logging
from collections import defaultdict
@@ -16,7 +17,9 @@ from six import text_type
from courseware import courses
from courseware.access import has_access
from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY, TYPE_SUBCATEGORY
from lms.djangoapps.discussion.django_comment_client.permissions import check_permissions_by_view, get_team, has_permission
from lms.djangoapps.discussion.django_comment_client.permissions import (
check_permissions_by_view, get_team, has_permission,
)
from lms.djangoapps.discussion.django_comment_client.settings import MAX_COMMENT_DEPTH
from django_comment_common.models import (
FORUM_ROLE_STUDENT,
@@ -271,7 +274,9 @@ def _filter_unstarted_categories(category_map, course):
if key != "start_date":
filtered_map["entries"][child][key] = unfiltered_map["entries"][child][key]
else:
log.debug(u"Filtering out:%s with start_date: %s", child, unfiltered_map["entries"][child]["start_date"])
log.debug(
u"Filtering out:%s with start_date: %s", child, unfiltered_map["entries"][child]["start_date"]
)
else:
if course.self_paced or unfiltered_map["subcategories"][child]["start_date"] < now:
filtered_map["children"].append((child, c_type))
@@ -568,7 +573,9 @@ def get_ability(course_id, content, user):
user_group_id,
content_user_group_id
),
'can_reply': check_permissions_by_view(user, course_id, content, "create_comment" if content['type'] == 'thread' else "create_sub_comment"),
'can_reply': check_permissions_by_view(
user, course_id, content, "create_comment" if content['type'] == 'thread' else "create_sub_comment",
),
'can_delete': check_permissions_by_view(
user,
course_id,

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
from __future__ import print_function
from django.contrib.auth.models import User

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
"""
This must be run only after seed_permissions_roles.py!

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
from courseware.courses import get_course
from django.core.management.base import BaseCommand, CommandError
from opaque_keys.edx.keys import CourseKey

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring,broad-except
"""
Reload forum (comment client) users from existing users.
"""

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
"""
Management command to seed default permissions and roles.
"""

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring,too-many-format-args
from __future__ import print_function
from django.contrib.auth.models import User

View File

@@ -1 +1,2 @@
# pylint: disable=missing-docstring
NOTIFICATION_PREF_KEY = "notification_pref"

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring,unused-argument,no-member
from django.contrib.auth.models import User
from lettuce import step, world

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring,consider-iterating-dictionary
import json
from django.contrib.auth.models import AnonymousUser

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
"""
Views to support notification preferences.
"""
@@ -90,7 +91,7 @@ class UsernameCipher(object):
try:
unpadded = unpadder.update(decrypted) + unpadder.finalize()
if len(unpadded) == 0:
if len(unpadded) == 0: # pylint: disable=len-as-condition
raise UsernameDecryptionException("padding")
return unpadded
except ValueError:

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
from django.contrib.auth.models import User
from django.http import Http404
from rest_framework import serializers

View File

@@ -1,3 +1,4 @@
# pylint: disable=missing-docstring
from __future__ import absolute_import
import itertools

View File

@@ -1,3 +1,6 @@
"""
Django views for the Notifier.
"""
from django.contrib.auth.models import User
from rest_framework import pagination
from rest_framework.response import Response

View File

@@ -3,29 +3,17 @@ Discussion API internal interface
"""
import itertools
from collections import defaultdict
from enum import Enum
from urllib import urlencode
from urlparse import urlunparse
from django.core.exceptions import ValidationError
from django.urls import reverse
from django.http import Http404
from enum import Enum
from opaque_keys import InvalidKeyError
from opaque_keys.edx.locator import CourseKey
from rest_framework.exceptions import PermissionDenied
from courseware.courses import get_course_with_access
from lms.djangoapps.discussion.rest_api.exceptions import CommentNotFoundError, DiscussionDisabledError, ThreadNotFoundError
from lms.djangoapps.discussion.rest_api.forms import CommentActionsForm, ThreadActionsForm
from lms.djangoapps.discussion.rest_api.permissions import (
can_delete,
get_editable_fields,
get_initializable_comment_fields,
get_initializable_thread_fields
)
from lms.djangoapps.discussion.rest_api.serializers import CommentSerializer, DiscussionTopicSerializer, ThreadSerializer, get_context
from lms.djangoapps.discussion.django_comment_client.base.views import track_comment_created_event, track_thread_created_event, track_voted_event
from lms.djangoapps.discussion.django_comment_client.utils import get_accessible_discussion_xblocks, get_group_id_for_user, is_commentable_divided
from django_comment_common.comment_client.comment import Comment
from django_comment_common.comment_client.thread import Thread
from django_comment_common.comment_client.utils import CommentClientRequestError
@@ -40,6 +28,27 @@ from django_comment_common.signals import (
thread_voted
)
from django_comment_common.utils import get_course_discussion_settings
from lms.djangoapps.courseware.courses import get_course_with_access
from lms.djangoapps.discussion.rest_api.exceptions import (
CommentNotFoundError, DiscussionDisabledError, ThreadNotFoundError,
)
from lms.djangoapps.discussion.rest_api.forms import CommentActionsForm, ThreadActionsForm
from lms.djangoapps.discussion.rest_api.permissions import (
can_delete,
get_editable_fields,
get_initializable_comment_fields,
get_initializable_thread_fields
)
from lms.djangoapps.discussion.rest_api.serializers import (
CommentSerializer, DiscussionTopicSerializer, ThreadSerializer, get_context,
)
from lms.djangoapps.discussion.django_comment_client.base.views import (
track_comment_created_event, track_thread_created_event, track_voted_event,
)
from lms.djangoapps.discussion.django_comment_client.utils import (
get_accessible_discussion_xblocks, get_group_id_for_user, is_commentable_divided,
)
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
from lms.djangoapps.discussion.rest_api.pagination import DiscussionAPIPagination
from openedx.core.djangoapps.user_api.accounts.views import AccountViewSet
@@ -1042,7 +1051,7 @@ def get_response_comments(request, comment_id, page, page_size, requested_fields
response_skip = page_size * (page - 1)
paged_response_comments = response_comments[response_skip:(response_skip + page_size)]
if len(paged_response_comments) == 0 and page != 1:
if not paged_response_comments and page != 1:
raise PageNotFoundError("Page not found (No results on this page).")
results = _serialize_discussion_entities(

View File

@@ -146,7 +146,7 @@ class CourseDiscussionSettingsForm(Form):
self.cleaned_data['course_key'] = course_key
return course_id
except InvalidKeyError:
raise ValidationError("'{}' is not a valid course key".format(text_type(course_id)))
raise ValidationError(u"'{}' is not a valid course key".format(text_type(course_id)))
class CourseDiscussionRolesForm(CourseDiscussionSettingsForm):
@@ -160,7 +160,7 @@ class CourseDiscussionRolesForm(CourseDiscussionSettingsForm):
)
rolename = ChoiceField(
ROLE_CHOICES,
error_messages={"invalid_choice": "Role '%(value)s' does not exist"}
error_messages={u"invalid_choice": u"Role '%(value)s' does not exist"}
)
def clean_rolename(self):
@@ -171,7 +171,7 @@ class CourseDiscussionRolesForm(CourseDiscussionSettingsForm):
try:
role = Role.objects.get(name=rolename, course_id=course_id)
except Role.DoesNotExist:
raise ValidationError("Role '{}' does not exist".format(rolename))
raise ValidationError(u"Role '{}' does not exist".format(rolename))
self.cleaned_data['role'] = role
return rolename

View File

@@ -9,10 +9,6 @@ from django.core.exceptions import ValidationError
from django.urls import reverse
from rest_framework import serializers
from discussion.views import get_divided_discussions
from lms.djangoapps.discussion.rest_api.permissions import NON_UPDATABLE_COMMENT_FIELDS, NON_UPDATABLE_THREAD_FIELDS, get_editable_fields
from lms.djangoapps.discussion.rest_api.render import render_body
from lms.djangoapps.discussion.django_comment_client.utils import is_comment_too_deep, get_group_id_for_user, get_group_name
from django_comment_common.models import (
FORUM_ROLE_ADMINISTRATOR,
FORUM_ROLE_COMMUNITY_TA,
@@ -24,7 +20,17 @@ from django_comment_common.comment_client.thread import Thread
from django_comment_common.comment_client.user import User as CommentClientUser
from django_comment_common.comment_client.utils import CommentClientRequestError
from django_comment_common.utils import get_course_discussion_settings
from lms.djangoapps.django_comment_client.utils import course_discussion_division_enabled, get_group_names_by_id
from lms.djangoapps.discussion.django_comment_client.utils import (
is_comment_too_deep, get_group_id_for_user, get_group_name,
)
from lms.djangoapps.discussion.rest_api.permissions import (
NON_UPDATABLE_COMMENT_FIELDS, NON_UPDATABLE_THREAD_FIELDS, get_editable_fields,
)
from lms.djangoapps.discussion.rest_api.render import render_body
from lms.djangoapps.discussion.views import get_divided_discussions
from lms.djangoapps.discussion.django_comment_client.utils import (
course_discussion_division_enabled, get_group_names_by_id,
)
from student.models import get_user_by_username_or_email
@@ -75,6 +81,7 @@ def validate_not_blank(value):
class _ContentSerializer(serializers.Serializer):
# pylint: disable=abstract-method
"""
A base class for thread and comment serializers.
"""
@@ -368,6 +375,7 @@ class CommentSerializer(_ContentSerializer):
]
def to_representation(self, data):
# pylint: disable=arguments-differ
data = super(CommentSerializer, self).to_representation(data)
# Django Rest Framework v3 no longer includes None values
@@ -529,7 +537,7 @@ class DiscussionRolesSerializer(serializers.Serializer):
self.user = get_user_by_username_or_email(user_id)
return user_id
except DjangoUser.DoesNotExist:
raise ValidationError("'{}' is not a valid student identifier".format(user_id))
raise ValidationError(u"'{}' is not a valid student identifier".format(user_id))
def validate(self, attrs):
"""Validate the data at an object level."""

View File

@@ -31,7 +31,9 @@ from lms.djangoapps.discussion.rest_api.api import (
update_comment,
update_thread
)
from lms.djangoapps.discussion.rest_api.exceptions import CommentNotFoundError, DiscussionDisabledError, ThreadNotFoundError
from lms.djangoapps.discussion.rest_api.exceptions import (
CommentNotFoundError, DiscussionDisabledError, ThreadNotFoundError,
)
from lms.djangoapps.discussion.rest_api.tests.utils import (
CommentsServiceMockMixin,
make_minimal_cs_comment,
@@ -1549,7 +1551,7 @@ class CreateThreadTest(
})
self.register_post_thread_response(cs_thread)
with self.assert_signal_sent(api, 'thread_created', sender=None, user=self.user, exclude_args=('post',)):
actual = create_thread(self.request, data)
create_thread(self.request, data)
event_name, event_data = mock_emit.call_args[0]
self.assertEqual(event_name, "edx.forum.thread.created")
self.assertEqual(

View File

@@ -10,7 +10,9 @@ import mock
from django.test.client import RequestFactory
from lms.djangoapps.discussion.rest_api.serializers import CommentSerializer, ThreadSerializer, get_context
from lms.djangoapps.discussion.rest_api.tests.utils import CommentsServiceMockMixin, make_minimal_cs_comment, make_minimal_cs_thread
from lms.djangoapps.discussion.rest_api.tests.utils import (
CommentsServiceMockMixin, make_minimal_cs_comment, make_minimal_cs_thread,
)
from lms.djangoapps.discussion.django_comment_client.tests.utils import ForumsEnableMixin
from django_comment_common.comment_client.comment import Comment
from django_comment_common.comment_client.thread import Thread
@@ -737,7 +739,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc
@ddt.data(None, -1, 0, 2, 5)
def test_create_parent_id_too_deep(self, max_depth):
with mock.patch("django_comment_client.utils.MAX_COMMENT_DEPTH", max_depth):
with mock.patch("lms.djangoapps.discussion.django_comment_client.utils.MAX_COMMENT_DEPTH", max_depth):
data = self.minimal_data.copy()
context = get_context(self.course, self.request, make_minimal_cs_thread())
if max_depth is None or max_depth >= 0:

View File

@@ -29,7 +29,9 @@ from lms.djangoapps.discussion.rest_api.tests.utils import (
make_minimal_cs_thread,
make_paginated_api_response
)
from lms.djangoapps.discussion.django_comment_client.tests.utils import ForumsEnableMixin, config_course_discussions, topic_name_to_id
from lms.djangoapps.discussion.django_comment_client.tests.utils import (
ForumsEnableMixin, config_course_discussions, topic_name_to_id,
)
from django_comment_common.models import CourseDiscussionSettings, Role
from django_comment_common.utils import seed_permissions_roles
from openedx.core.djangoapps.course_groups.tests.helpers import config_course_cohorts

View File

@@ -521,7 +521,7 @@ class ProfileImageTestMixin(object):
self.assertTrue(storage.exists(name))
with closing(Image.open(storage.path(name))) as img:
self.assertEqual(img.size, (size, size))
self.assertEqual(img.format, 'JPEG')
self.assertEqual(img.format, 'JPEG') # pylint: disable=no-member
else:
self.assertFalse(storage.exists(name))

View File

@@ -1,3 +1,4 @@
# pylint: skip-file
"""
Discussion API URLs
"""
@@ -29,7 +30,7 @@ urlpatterns = [
name="discussion_course_settings",
),
url(
r'^v1/courses/{}/roles/(?P<rolename>[A-Za-z0-9+ _-]+)/?$'.format(
r"^v1/courses/{}/roles/(?P<rolename>[A-Za-z0-9+ _-]+)/?$".format(
settings.COURSE_ID_PATTERN
),
CourseDiscussionRolesAPIView.as_view(),

View File

@@ -17,13 +17,13 @@ from rest_framework.views import APIView
from rest_framework.viewsets import ViewSet
from six import text_type
from lms.djangoapps.discussion.django_comment_client.utils import available_division_schemes
from django_comment_common import comment_client
from django_comment_common.models import Role
from django_comment_common.utils import get_course_discussion_settings, set_course_discussion_settings
from instructor.access import update_forum_role
from discussion.views import get_divided_discussions
from lms.djangoapps.discussion.django_comment_client.utils import available_division_schemes
from lms.djangoapps.discussion.rest_api.api import (
create_comment,
create_thread,
@@ -930,7 +930,7 @@ class CourseDiscussionRolesAPIView(DeveloperErrorViewMixin, APIView):
try:
update_forum_role(course_id, user, rolename, action)
except Role.DoesNotExist:
raise ValidationError("Role '{}' does not exist".format(rolename))
raise ValidationError(u"Role '{}' does not exist".format(rolename))
role = form.cleaned_data['role']
data = {'course_id': course_id, 'users': role.users.all()}

View File

@@ -17,7 +17,9 @@ from edx_ace import ace
from edx_ace.utils import date
from edx_ace.recipient import Recipient
from eventtracking import tracker
from lms.djangoapps.django_comment_client.utils import permalink, get_accessible_discussion_xblocks_by_course_id
from lms.djangoapps.discussion.django_comment_client.utils import (
permalink, get_accessible_discussion_xblocks_by_course_id,
)
from opaque_keys.edx.keys import CourseKey
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview

View File

@@ -23,12 +23,13 @@ from opaque_keys.edx.keys import CourseKey
from rest_framework import status
from web_fragments.fragment import Fragment
import lms.djangoapps.discussion.django_comment_client.utils as utils
import django_comment_common.comment_client as cc
from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context
from courseware.access import has_access
from courseware.courses import get_course_with_access
from courseware.views.views import CourseTabView
import django_comment_common.comment_client as cc
from django_comment_common.models import CourseDiscussionSettings
from django_comment_common.utils import ThreadContext, get_course_discussion_settings, set_course_discussion_settings
import lms.djangoapps.discussion.django_comment_client.utils as utils
from lms.djangoapps.discussion.django_comment_client.base.views import track_thread_viewed_event
from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY
from lms.djangoapps.discussion.django_comment_client.permissions import get_team, has_permission
@@ -43,8 +44,7 @@ from lms.djangoapps.discussion.django_comment_client.utils import (
is_commentable_divided,
strip_none
)
from django_comment_common.models import CourseDiscussionSettings
from django_comment_common.utils import ThreadContext, get_course_discussion_settings, set_course_discussion_settings
from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
from openedx.features.course_duration_limits.access import generate_course_expired_fragment
from student.models import CourseEnrollment

View File

@@ -1,7 +1,7 @@
<%page expression_filter="h"/>
<%!
from django.utils.translation import ugettext as _
from lms.djangoapps.django_comment_client.constants import TYPE_ENTRY
from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY
from openedx.core.djangolib.markup import HTML
%>