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
90fe71db
Commit
90fe71db
authored
Sep 15, 2015
by
wajeeha-khalid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MA-1248 - CourseEnrollmentAPI: added discussion URL
parent
06129ada
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
168 additions
and
24 deletions
+168
-24
common/djangoapps/xmodule_django/models.py
+0
-1
lms/djangoapps/discussion_api/api.py
+2
-2
lms/djangoapps/discussion_api/tests/test_api.py
+12
-12
lms/djangoapps/discussion_api/tests/test_views.py
+11
-0
lms/djangoapps/django_comment_client/forum/views.py
+1
-6
lms/djangoapps/django_comment_client/utils.py
+12
-0
lms/djangoapps/mobile_api/users/serializers.py
+7
-0
lms/djangoapps/mobile_api/users/tests.py
+17
-1
lms/djangoapps/mobile_api/users/views.py
+2
-0
openedx/core/djangoapps/content/course_overviews/migrations/0007_auto__add_courseoverviewtab.py
+69
-0
openedx/core/djangoapps/content/course_overviews/models.py
+27
-2
openedx/core/djangoapps/content/course_overviews/tests.py
+8
-0
No files found.
common/djangoapps/xmodule_django/models.py
View file @
90fe71db
"""
Useful django models for implementing XBlock infrastructure in django.
"""
import
warnings
from
django.db
import
models
...
...
lms/djangoapps/discussion_api/api.py
View file @
90fe71db
...
...
@@ -13,8 +13,8 @@ from rest_framework.exceptions import PermissionDenied
from
opaque_keys
import
InvalidKeyError
from
opaque_keys.edx.locator
import
CourseKey
from
courseware.courses
import
get_course_with_access
from
discussion_api.forms
import
CommentActionsForm
,
ThreadActionsForm
from
discussion_api.pagination
import
get_paginated_data
from
discussion_api.permissions
import
(
...
...
@@ -55,7 +55,7 @@ def _get_course_or_404(course_key, user):
disabled for the course.
"""
course
=
get_course_with_access
(
user
,
'load'
,
course_key
,
check_if_enrolled
=
True
)
if
not
any
([
tab
.
type
==
'discussion'
for
tab
in
course
.
tabs
]):
if
not
any
([
tab
.
type
==
'discussion'
and
tab
.
is_enabled
(
course
,
user
)
for
tab
in
course
.
tabs
]):
raise
Http404
return
course
...
...
lms/djangoapps/discussion_api/tests/test_api.py
View file @
90fe71db
...
...
@@ -81,11 +81,11 @@ def _discussion_disabled_course_for(user):
@ddt.ddt
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
GetCourseTest
(
UrlResetMixin
,
SharedModuleStoreTestCase
):
"""Test for get_course"""
@classmethod
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUpClass
(
cls
):
super
(
GetCourseTest
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
(
org
=
"x"
,
course
=
"y"
,
run
=
"z"
)
...
...
@@ -154,9 +154,9 @@ class GetCourseTest(UrlResetMixin, SharedModuleStoreTestCase):
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"DISABLE_START_DATES"
:
False
})
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
GetCourseTopicsTest
(
UrlResetMixin
,
ModuleStoreTestCase
):
"""Test for get_course_topics"""
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUp
(
self
):
super
(
GetCourseTopicsTest
,
self
)
.
setUp
()
...
...
@@ -480,11 +480,11 @@ class GetCourseTopicsTest(UrlResetMixin, ModuleStoreTestCase):
@ddt.ddt
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
GetThreadListTest
(
CommentsServiceMockMixin
,
UrlResetMixin
,
SharedModuleStoreTestCase
):
"""Test for get_thread_list"""
@classmethod
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUpClass
(
cls
):
super
(
GetThreadListTest
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
...
...
@@ -909,15 +909,16 @@ class GetThreadListTest(CommentsServiceMockMixin, UrlResetMixin, SharedModuleSto
@ddt.ddt
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
GetCommentListTest
(
CommentsServiceMockMixin
,
SharedModuleStoreTestCase
):
"""Test for get_comment_list"""
@classmethod
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUpClass
(
cls
):
super
(
GetCommentListTest
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUp
(
self
):
super
(
GetCommentListTest
,
self
)
.
setUp
()
httpretty
.
reset
()
...
...
@@ -1333,6 +1334,7 @@ class GetCommentListTest(CommentsServiceMockMixin, SharedModuleStoreTestCase):
@ddt.ddt
@disable_signal
(
api
,
'thread_created'
)
@disable_signal
(
api
,
'thread_voted'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
CreateThreadTest
(
CommentsServiceMockMixin
,
UrlResetMixin
,
...
...
@@ -1341,7 +1343,6 @@ class CreateThreadTest(
):
"""Tests for create_thread"""
@classmethod
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUpClass
(
cls
):
super
(
CreateThreadTest
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
...
...
@@ -1585,6 +1586,7 @@ class CreateThreadTest(
@ddt.ddt
@disable_signal
(
api
,
'comment_created'
)
@disable_signal
(
api
,
'comment_voted'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
CreateCommentTest
(
CommentsServiceMockMixin
,
UrlResetMixin
,
...
...
@@ -1593,7 +1595,6 @@ class CreateCommentTest(
):
"""Tests for create_comment"""
@classmethod
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUpClass
(
cls
):
super
(
CreateCommentTest
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
...
...
@@ -1859,6 +1860,7 @@ class CreateCommentTest(
@ddt.ddt
@disable_signal
(
api
,
'thread_edited'
)
@disable_signal
(
api
,
'thread_voted'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
UpdateThreadTest
(
CommentsServiceMockMixin
,
UrlResetMixin
,
...
...
@@ -1867,7 +1869,6 @@ class UpdateThreadTest(
):
"""Tests for update_thread"""
@classmethod
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUpClass
(
cls
):
super
(
UpdateThreadTest
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
...
...
@@ -2247,6 +2248,7 @@ class UpdateThreadTest(
@ddt.ddt
@disable_signal
(
api
,
'comment_edited'
)
@disable_signal
(
api
,
'comment_voted'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
UpdateCommentTest
(
CommentsServiceMockMixin
,
UrlResetMixin
,
...
...
@@ -2256,7 +2258,6 @@ class UpdateCommentTest(
"""Tests for update_comment"""
@classmethod
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUpClass
(
cls
):
super
(
UpdateCommentTest
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
...
...
@@ -2304,7 +2305,6 @@ class UpdateCommentTest(
self
.
register_get_comment_response
(
cs_comment_data
)
self
.
register_put_comment_response
(
cs_comment_data
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
test_empty
(
self
):
"""Check that an empty update does not make any modifying requests."""
self
.
register_comment
()
...
...
@@ -2632,6 +2632,7 @@ class UpdateCommentTest(
@ddt.ddt
@disable_signal
(
api
,
'thread_deleted'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
DeleteThreadTest
(
CommentsServiceMockMixin
,
UrlResetMixin
,
...
...
@@ -2640,7 +2641,6 @@ class DeleteThreadTest(
):
"""Tests for delete_thread"""
@classmethod
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUpClass
(
cls
):
super
(
DeleteThreadTest
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
...
...
@@ -2771,6 +2771,7 @@ class DeleteThreadTest(
@ddt.ddt
@disable_signal
(
api
,
'comment_deleted'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
DeleteCommentTest
(
CommentsServiceMockMixin
,
UrlResetMixin
,
...
...
@@ -2779,7 +2780,6 @@ class DeleteCommentTest(
):
"""Tests for delete_comment"""
@classmethod
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUpClass
(
cls
):
super
(
DeleteCommentTest
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
...
...
@@ -2928,6 +2928,7 @@ class DeleteCommentTest(
@ddt.ddt
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
RetrieveThreadTest
(
CommentsServiceMockMixin
,
UrlResetMixin
,
...
...
@@ -2935,7 +2936,6 @@ class RetrieveThreadTest(
):
"""Tests for get_thread"""
@classmethod
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUpClass
(
cls
):
super
(
RetrieveThreadTest
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
...
...
lms/djangoapps/discussion_api/tests/test_views.py
View file @
90fe71db
...
...
@@ -70,6 +70,7 @@ class DiscussionAPIViewTestMixin(CommentsServiceMockMixin, UrlResetMixin):
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
CourseViewTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for CourseView"""
def
setUp
(
self
):
...
...
@@ -103,6 +104,7 @@ class CourseViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
CourseTopicsViewTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for CourseTopicsView"""
def
setUp
(
self
):
...
...
@@ -139,6 +141,7 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
@ddt.ddt
@httpretty.activate
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
ThreadViewSetListTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for ThreadViewSet list"""
def
setUp
(
self
):
...
...
@@ -388,6 +391,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
@httpretty.activate
@disable_signal
(
api
,
'thread_created'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
ThreadViewSetCreateTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for ThreadViewSet create"""
def
setUp
(
self
):
...
...
@@ -480,6 +484,7 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
@httpretty.activate
@disable_signal
(
api
,
'thread_edited'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
ThreadViewSetPartialUpdateTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for ThreadViewSet partial_update"""
def
setUp
(
self
):
...
...
@@ -580,6 +585,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
@httpretty.activate
@disable_signal
(
api
,
'thread_deleted'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
ThreadViewSetDeleteTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for ThreadViewSet delete"""
def
setUp
(
self
):
...
...
@@ -613,6 +619,7 @@ class ThreadViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
@httpretty.activate
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
CommentViewSetListTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for CommentViewSet list"""
def
setUp
(
self
):
...
...
@@ -744,6 +751,7 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
@httpretty.activate
@disable_signal
(
api
,
'comment_deleted'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
CommentViewSetDeleteTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for ThreadViewSet delete"""
...
...
@@ -785,6 +793,7 @@ class CommentViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
@httpretty.activate
@disable_signal
(
api
,
'comment_created'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
CommentViewSetCreateTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for CommentViewSet create"""
def
setUp
(
self
):
...
...
@@ -869,6 +878,7 @@ class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
@disable_signal
(
api
,
'comment_edited'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
CommentViewSetPartialUpdateTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for CommentViewSet partial_update"""
def
setUp
(
self
):
...
...
@@ -954,6 +964,7 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes
@httpretty.activate
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
ThreadViewSetRetrieveTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
"""Tests for ThreadViewSet Retrieve"""
def
setUp
(
self
):
...
...
lms/djangoapps/django_comment_client/forum/views.py
View file @
90fe71db
...
...
@@ -27,7 +27,6 @@ from openedx.core.djangoapps.course_groups.cohorts import (
from
courseware.tabs
import
EnrolledTab
from
courseware.access
import
has_access
from
xmodule.modulestore.django
import
modulestore
from
ccx.overrides
import
get_current_ccx
from
django_comment_common.utils
import
ThreadContext
from
django_comment_client.permissions
import
has_permission
,
get_team
...
...
@@ -66,11 +65,7 @@ class DiscussionTab(EnrolledTab):
def
is_enabled
(
cls
,
course
,
user
=
None
):
if
not
super
(
DiscussionTab
,
cls
)
.
is_enabled
(
course
,
user
):
return
False
if
settings
.
FEATURES
.
get
(
'CUSTOM_COURSES_EDX'
,
False
):
if
get_current_ccx
(
course
.
id
):
return
False
return
settings
.
FEATURES
.
get
(
'ENABLE_DISCUSSION_SERVICE'
)
return
utils
.
is_discussion_enabled
(
course
.
id
)
def
_attr_safe_json
(
obj
):
...
...
lms/djangoapps/django_comment_client/utils.py
View file @
90fe71db
...
...
@@ -2,6 +2,7 @@ from collections import defaultdict
from
datetime
import
datetime
import
json
import
logging
from
django.conf
import
settings
import
pytz
from
django.contrib.auth.models
import
User
...
...
@@ -13,6 +14,7 @@ import pystache_custom as pystache
from
opaque_keys.edx.locations
import
i4xEncoder
from
opaque_keys.edx.keys
import
CourseKey
from
xmodule.modulestore.django
import
modulestore
from
ccx.overrides
import
get_current_ccx
from
django_comment_common.models
import
Role
,
FORUM_ROLE_STUDENT
from
django_comment_client.permissions
import
check_permissions_by_view
,
has_permission
,
get_team
...
...
@@ -716,3 +718,13 @@ def is_commentable_cohorted(course_key, commentable_id):
log
.
debug
(
u"is_commentable_cohorted(
%
s,
%
s) = {
%
s}"
,
course_key
,
commentable_id
,
ans
)
return
ans
def
is_discussion_enabled
(
course_id
):
"""
Return True if Discussion is enabled for a course; else False
"""
if
settings
.
FEATURES
.
get
(
'CUSTOM_COURSES_EDX'
,
False
):
if
get_current_ccx
(
course_id
):
return
False
return
settings
.
FEATURES
.
get
(
'ENABLE_DISCUSSION_SERVICE'
)
lms/djangoapps/mobile_api/users/serializers.py
View file @
90fe71db
...
...
@@ -34,10 +34,16 @@ class CourseOverviewField(serializers.RelatedField):
kwargs
=
{
'course_id'
:
course_id
},
request
=
request
)
discussion_url
=
reverse
(
'discussion_course'
,
kwargs
=
{
'course_id'
:
course_id
},
request
=
request
)
if
course_overview
.
is_discussion_tab_enabled
()
else
None
else
:
video_outline_url
=
None
course_updates_url
=
None
course_handouts_url
=
None
discussion_url
=
None
if
course_overview
.
advertised_start
is
not
None
:
start_type
=
"string"
...
...
@@ -68,6 +74,7 @@ class CourseOverviewField(serializers.RelatedField):
"video_outline"
:
video_outline_url
,
"course_updates"
:
course_updates_url
,
"course_handouts"
:
course_handouts_url
,
"discussion_url"
:
discussion_url
,
"subscription_id"
:
course_overview
.
clean_id
(
padding_char
=
'_'
),
"courseware_access"
:
has_access
(
request
.
user
,
'load_mobile'
,
course_overview
)
.
to_json
()
if
request
else
None
}
...
...
lms/djangoapps/mobile_api/users/tests.py
View file @
90fe71db
...
...
@@ -28,6 +28,7 @@ from xmodule.modulestore.tests.factories import ItemFactory, CourseFactory
from
..
import
errors
from
..testutils
import
MobileAPITestCase
,
MobileAuthTestMixin
,
MobileAuthUserTestMixin
,
MobileCourseAccessTestMixin
from
.serializers
import
CourseEnrollmentSerializer
from
util.testing
import
UrlResetMixin
class
TestUserDetailApi
(
MobileAPITestCase
,
MobileAuthUserTestMixin
):
...
...
@@ -60,7 +61,7 @@ class TestUserInfoApi(MobileAPITestCase, MobileAuthTestMixin):
@ddt.ddt
class
TestUserEnrollmentApi
(
MobileAPITestCase
,
MobileAuthUserTestMixin
):
class
TestUserEnrollmentApi
(
UrlResetMixin
,
MobileAPITestCase
,
MobileAuthUserTestMixin
):
"""
Tests for /api/mobile/v0.5/users/<user_name>/course_enrollments/
"""
...
...
@@ -71,7 +72,14 @@ class TestUserEnrollmentApi(MobileAPITestCase, MobileAuthUserTestMixin):
LAST_WEEK
=
datetime
.
datetime
.
now
(
pytz
.
UTC
)
-
datetime
.
timedelta
(
days
=
7
)
ADVERTISED_START
=
"Spring 2016"
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUp
(
self
,
*
args
,
**
kwargs
):
super
(
TestUserEnrollmentApi
,
self
)
.
setUp
()
def
verify_success
(
self
,
response
):
"""
Verifies user course enrollment response for success
"""
super
(
TestUserEnrollmentApi
,
self
)
.
verify_success
(
response
)
courses
=
response
.
data
self
.
assertEqual
(
len
(
courses
),
1
)
...
...
@@ -205,6 +213,14 @@ class TestUserEnrollmentApi(MobileAPITestCase, MobileAuthUserTestMixin):
course_data
=
response
.
data
[
0
][
'course'
]
self
.
assertEquals
(
course_data
[
'social_urls'
][
'facebook'
],
self
.
course
.
facebook_url
)
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
test_discussion_url
(
self
):
self
.
login_and_enroll
()
response
=
self
.
api_response
()
response_discussion_url
=
response
.
data
[
0
][
'course'
][
'discussion_url'
]
# pylint: disable=E1101
self
.
assertIn
(
'/api/discussion/v1/courses/{}'
.
format
(
self
.
course
.
id
),
response_discussion_url
)
class
CourseStatusAPITestCase
(
MobileAPITestCase
):
"""
...
...
lms/djangoapps/mobile_api/users/views.py
View file @
90fe71db
...
...
@@ -239,6 +239,8 @@ class UserCourseEnrollmentsList(generics.ListAPIView):
the course.
* video_outline: The URI to get the list of all videos that the user
can access in the course.
* discussion_url: The URI to access data for course discussions if
it is enabled, otherwise null.
* created: The date the course was created.
* is_active: Whether the course is currently active. Possible values
...
...
openedx/core/djangoapps/content/course_overviews/migrations/0007_auto__add_courseoverviewtab.py
0 → 100644
View file @
90fe71db
# -*- coding: utf-8 -*-
from
south.utils
import
datetime_utils
as
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Adding model 'CourseOverviewTab'
db
.
create_table
(
'course_overviews_courseoverviewtab'
,
(
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'tab_id'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
50
)),
(
'course_overview'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
related_name
=
'tabs'
,
to
=
orm
[
'course_overviews.CourseOverview'
])),
))
db
.
send_create_signal
(
'course_overviews'
,
[
'CourseOverviewTab'
])
def
backwards
(
self
,
orm
):
# Deleting model 'CourseOverviewTab'
db
.
delete_table
(
'course_overviews_courseoverviewtab'
)
models
=
{
'course_overviews.courseoverview'
:
{
'Meta'
:
{
'object_name'
:
'CourseOverview'
},
'_location'
:
(
'xmodule_django.models.UsageKeyField'
,
[],
{
'max_length'
:
'255'
}),
'_pre_requisite_courses_json'
:
(
'django.db.models.fields.TextField'
,
[],
{}),
'advertised_start'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
}),
'cert_html_view_enabled'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'cert_name_long'
:
(
'django.db.models.fields.TextField'
,
[],
{}),
'cert_name_short'
:
(
'django.db.models.fields.TextField'
,
[],
{}),
'certificates_display_behavior'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
}),
'certificates_show_before_end'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'course_image_url'
:
(
'django.db.models.fields.TextField'
,
[],
{}),
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'days_early_for_beta'
:
(
'django.db.models.fields.FloatField'
,
[],
{
'null'
:
'True'
}),
'display_name'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
}),
'display_number_with_default'
:
(
'django.db.models.fields.TextField'
,
[],
{}),
'display_org_with_default'
:
(
'django.db.models.fields.TextField'
,
[],
{}),
'end'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
}),
'end_of_course_survey_url'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
}),
'enrollment_domain'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
}),
'enrollment_end'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
}),
'enrollment_start'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
}),
'facebook_url'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
}),
'has_any_active_web_certificate'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'id'
:
(
'xmodule_django.models.CourseKeyField'
,
[],
{
'max_length'
:
'255'
,
'primary_key'
:
'True'
,
'db_index'
:
'True'
}),
'invitation_only'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'lowest_passing_grade'
:
(
'django.db.models.fields.DecimalField'
,
[],
{
'null'
:
'True'
,
'max_digits'
:
'5'
,
'decimal_places'
:
'2'
}),
'max_student_enrollments_allowed'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'null'
:
'True'
}),
'mobile_available'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'social_sharing_url'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
}),
'start'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
}),
'version'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'visible_to_staff_only'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
})
},
'course_overviews.courseoverviewtab'
:
{
'Meta'
:
{
'object_name'
:
'CourseOverviewTab'
},
'course_overview'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'related_name'
:
"'tabs'"
,
'to'
:
"orm['course_overviews.CourseOverview']"
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'tab_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
}
}
complete_apps
=
[
'course_overviews'
]
\ No newline at end of file
openedx/core/djangoapps/content/course_overviews/models.py
View file @
90fe71db
"""
Declaration of CourseOverview model
"""
import
json
from
django.db
import
models
from
django.db.models.fields
import
BooleanField
,
DateTimeField
,
DecimalField
,
TextField
,
FloatField
,
IntegerField
from
django.db.utils
import
IntegrityError
from
django.utils.translation
import
ugettext
from
lms.djangoapps
import
django_comment_client
from
model_utils.models
import
TimeStampedModel
from
opaque_keys.edx.keys
import
CourseKey
from
util.date_utils
import
strftime_localized
from
xmodule
import
course_metadata_utils
from
xmodule.course_module
import
CourseDescriptor
...
...
@@ -30,7 +32,7 @@ class CourseOverview(TimeStampedModel):
"""
# IMPORTANT: Bump this whenever you modify this model and/or add a migration.
VERSION
=
1
VERSION
=
2
# Cache entry versioning.
version
=
IntegerField
()
...
...
@@ -176,6 +178,10 @@ class CourseOverview(TimeStampedModel):
course_overview
=
cls
.
_create_from_course
(
course
)
try
:
course_overview
.
save
()
CourseOverviewTab
.
objects
.
bulk_create
([
CourseOverviewTab
(
tab_id
=
tab
.
tab_id
,
course_overview
=
course_overview
)
for
tab
in
course
.
tabs
])
except
IntegrityError
:
# There is a rare race condition that will occur if
# CourseOverview.get_from_id is called while a
...
...
@@ -358,3 +364,22 @@ class CourseOverview(TimeStampedModel):
CourseKey
.
from_string
(
course_overview
[
'id'
])
for
course_overview
in
CourseOverview
.
objects
.
values
(
'id'
)
]
def
is_discussion_tab_enabled
(
self
):
"""
Returns True if course has discussion tab and is enabled
"""
tabs
=
self
.
tabs
.
all
()
# pylint: disable=E1101
# creates circular import; hence explicitly referenced is_discussion_enabled
for
tab
in
tabs
:
if
tab
.
tab_id
==
"discussion"
and
django_comment_client
.
utils
.
is_discussion_enabled
(
self
.
id
):
return
True
return
False
class
CourseOverviewTab
(
models
.
Model
):
"""
Model for storing and caching tabs information of a course.
"""
tab_id
=
models
.
CharField
(
max_length
=
50
)
course_overview
=
models
.
ForeignKey
(
CourseOverview
,
db_index
=
True
,
related_name
=
"tabs"
)
openedx/core/djangoapps/content/course_overviews/tests.py
View file @
90fe71db
...
...
@@ -34,6 +34,8 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
NEXT_WEEK
=
TODAY
+
datetime
.
timedelta
(
days
=
7
)
NEXT_MONTH
=
TODAY
+
datetime
.
timedelta
(
days
=
30
)
COURSE_OVERVIEW_TABS
=
{
'courseware'
,
'info'
,
'textbooks'
,
'discussion'
,
'wiki'
,
'progress'
}
def
check_course_overview_against_course
(
self
,
course
):
"""
Compares a CourseOverview object against its corresponding
...
...
@@ -164,6 +166,12 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
self
.
assertEqual
(
course_value
,
cache_miss_value
)
self
.
assertEqual
(
cache_miss_value
,
cache_hit_value
)
# test tabs for both cached miss and cached hit courses
for
course_overview
in
[
course_overview_cache_miss
,
course_overview_cache_hit
]:
course_overview_tabs
=
course_overview
.
tabs
.
all
()
course_resp_tabs
=
{
tab
.
tab_id
for
tab
in
course_overview_tabs
}
self
.
assertEqual
(
self
.
COURSE_OVERVIEW_TABS
,
course_resp_tabs
)
@ddt.data
(
*
itertools
.
product
(
[
{
...
...
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