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
8394fb71
Commit
8394fb71
authored
Jan 16, 2015
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6608 from edx/mobile/MA-216
MA-216 Mobile API: display unreleased courses in enrollment list.
parents
314ad957
dea6b764
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
60 additions
and
84 deletions
+60
-84
lms/djangoapps/courseware/access.py
+15
-5
lms/djangoapps/mobile_api/tests.py
+1
-41
lms/djangoapps/mobile_api/testutils.py
+13
-11
lms/djangoapps/mobile_api/users/tests.py
+19
-1
lms/djangoapps/mobile_api/users/views.py
+12
-9
lms/djangoapps/mobile_api/utils.py
+0
-17
No files found.
lms/djangoapps/courseware/access.py
View file @
8394fb71
...
@@ -166,11 +166,7 @@ def _has_access_course_desc(user, action, course):
...
@@ -166,11 +166,7 @@ def _has_access_course_desc(user, action, course):
# check start date
# check start date
can_load
()
and
can_load
()
and
# check mobile_available flag
# check mobile_available flag
(
is_mobile_available_for_user
(
user
,
course
)
course
.
mobile_available
or
auth
.
has_access
(
user
,
CourseBetaTesterRole
(
course
.
id
))
or
_has_staff_access_to_descriptor
(
user
,
course
,
course
.
id
)
)
)
)
def
can_enroll
():
def
can_enroll
():
...
@@ -649,6 +645,20 @@ def _has_staff_access_to_descriptor(user, descriptor, course_key):
...
@@ -649,6 +645,20 @@ def _has_staff_access_to_descriptor(user, descriptor, course_key):
return
_has_staff_access_to_location
(
user
,
descriptor
.
location
,
course_key
)
return
_has_staff_access_to_location
(
user
,
descriptor
.
location
,
course_key
)
def
is_mobile_available_for_user
(
user
,
course
):
"""
Returns whether the given course is mobile_available for the given user.
Checks:
mobile_available flag on the course
Beta User and staff access overrides the mobile_available flag
"""
return
(
course
.
mobile_available
or
auth
.
has_access
(
user
,
CourseBetaTesterRole
(
course
.
id
))
or
_has_staff_access_to_descriptor
(
user
,
course
,
course
.
id
)
)
def
get_user_role
(
user
,
course_key
):
def
get_user_role
(
user
,
course_key
):
"""
"""
Return corresponding string if user has staff, instructor or student
Return corresponding string if user has staff, instructor or student
...
...
lms/djangoapps/mobile_api/tests.py
View file @
8394fb71
...
@@ -3,49 +3,9 @@ Tests for mobile API utilities.
...
@@ -3,49 +3,9 @@ Tests for mobile API utilities.
"""
"""
import
ddt
import
ddt
from
mock
import
patch
from
django.test
import
TestCase
from
django.test
import
TestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
.utils
import
mobile_course_access
,
mobile_view
from
.utils
import
mobile_access_when_enrolled
,
mobile_course_access
,
mobile_view
from
.testutils
import
MobileAPITestCase
,
ROLE_CASES
@ddt.ddt
class
TestMobileAccessWhenEnrolled
(
MobileAPITestCase
):
"""
Tests for mobile_access_when_enrolled utility function.
"""
@ddt.data
(
*
ROLE_CASES
)
@ddt.unpack
def
test_mobile_role_access
(
self
,
role
,
should_have_access
):
"""
Verifies that our mobile access function properly handles using roles to grant access
"""
non_mobile_course
=
CourseFactory
.
create
(
mobile_available
=
False
)
if
role
:
role
(
non_mobile_course
.
id
)
.
add_users
(
self
.
user
)
self
.
assertEqual
(
should_have_access
,
mobile_access_when_enrolled
(
non_mobile_course
,
self
.
user
))
def
test_mobile_explicit_access
(
self
):
"""
Verifies that our mobile access function listens to the mobile_available flag as it should
"""
self
.
assertTrue
(
mobile_access_when_enrolled
(
self
.
course
,
self
.
user
))
def
test_missing_course
(
self
):
"""
Verifies that we handle the case where a course doesn't exist
"""
self
.
assertFalse
(
mobile_access_when_enrolled
(
None
,
self
.
user
))
@patch.dict
(
'django.conf.settings.FEATURES'
,
{
'DISABLE_START_DATES'
:
False
})
def
test_unreleased_course
(
self
):
"""
Verifies that we handle the case where a course hasn't started
"""
self
.
assertFalse
(
mobile_access_when_enrolled
(
self
.
course
,
self
.
user
))
@ddt.ddt
@ddt.ddt
...
...
lms/djangoapps/mobile_api/testutils.py
View file @
8394fb71
...
@@ -26,15 +26,6 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
...
@@ -26,15 +26,6 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
# A tuple of Role Types and Boolean values that indicate whether access should be given to that role.
ROLE_CASES
=
(
(
auth
.
CourseBetaTesterRole
,
True
),
(
auth
.
CourseStaffRole
,
True
),
(
auth
.
CourseInstructorRole
,
True
),
(
None
,
False
)
)
class
MobileAPITestCase
(
ModuleStoreTestCase
,
APITestCase
):
class
MobileAPITestCase
(
ModuleStoreTestCase
,
APITestCase
):
"""
"""
Base class for testing Mobile APIs.
Base class for testing Mobile APIs.
...
@@ -140,6 +131,8 @@ class MobileCourseAccessTestMixin(object):
...
@@ -140,6 +131,8 @@ class MobileCourseAccessTestMixin(object):
Subclasses are expected to inherit from MobileAPITestCase.
Subclasses are expected to inherit from MobileAPITestCase.
Subclasses can override verify_success, verify_failure, and init_course_access methods.
Subclasses can override verify_success, verify_failure, and init_course_access methods.
"""
"""
ALLOW_ACCESS_TO_UNRELEASED_COURSE
=
False
# pylint: disable=invalid-name
def
verify_success
(
self
,
response
):
def
verify_success
(
self
,
response
):
"""Base implementation of verifying a successful response."""
"""Base implementation of verifying a successful response."""
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
...
@@ -170,9 +163,18 @@ class MobileCourseAccessTestMixin(object):
...
@@ -170,9 +163,18 @@ class MobileCourseAccessTestMixin(object):
self
.
init_course_access
()
self
.
init_course_access
()
response
=
self
.
api_response
(
expected_response_code
=
None
)
response
=
self
.
api_response
(
expected_response_code
=
None
)
self
.
verify_failure
(
response
)
# allow subclasses to override verification
if
self
.
ALLOW_ACCESS_TO_UNRELEASED_COURSE
:
self
.
verify_success
(
response
)
else
:
self
.
verify_failure
(
response
)
@ddt.data
(
*
ROLE_CASES
)
# A tuple of Role Types and Boolean values that indicate whether access should be given to that role.
@ddt.data
(
(
auth
.
CourseBetaTesterRole
,
True
),
(
auth
.
CourseStaffRole
,
True
),
(
auth
.
CourseInstructorRole
,
True
),
(
None
,
False
)
)
@ddt.unpack
@ddt.unpack
def
test_non_mobile_available
(
self
,
role
,
should_succeed
):
def
test_non_mobile_available
(
self
,
role
,
should_succeed
):
self
.
init_course_access
()
self
.
init_course_access
()
...
...
lms/djangoapps/mobile_api/users/tests.py
View file @
8394fb71
...
@@ -5,7 +5,7 @@ Tests for users API
...
@@ -5,7 +5,7 @@ Tests for users API
import
datetime
import
datetime
from
django.utils
import
timezone
from
django.utils
import
timezone
from
xmodule.modulestore.tests.factories
import
ItemFactory
from
xmodule.modulestore.tests.factories
import
ItemFactory
,
CourseFactory
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
student.models
import
CourseEnrollment
from
student.models
import
CourseEnrollment
...
@@ -48,6 +48,7 @@ class TestUserEnrollmentApi(MobileAPITestCase, MobileAuthUserTestMixin, MobileEn
...
@@ -48,6 +48,7 @@ class TestUserEnrollmentApi(MobileAPITestCase, MobileAuthUserTestMixin, MobileEn
Tests for /api/mobile/v0.5/users/<user_name>/course_enrollments/
Tests for /api/mobile/v0.5/users/<user_name>/course_enrollments/
"""
"""
REVERSE_INFO
=
{
'name'
:
'courseenrollment-detail'
,
'params'
:
[
'username'
]}
REVERSE_INFO
=
{
'name'
:
'courseenrollment-detail'
,
'params'
:
[
'username'
]}
ALLOW_ACCESS_TO_UNRELEASED_COURSE
=
True
def
verify_success
(
self
,
response
):
def
verify_success
(
self
,
response
):
super
(
TestUserEnrollmentApi
,
self
)
.
verify_success
(
response
)
super
(
TestUserEnrollmentApi
,
self
)
.
verify_success
(
response
)
...
@@ -65,6 +66,23 @@ class TestUserEnrollmentApi(MobileAPITestCase, MobileAuthUserTestMixin, MobileEn
...
@@ -65,6 +66,23 @@ class TestUserEnrollmentApi(MobileAPITestCase, MobileAuthUserTestMixin, MobileEn
courses
=
response
.
data
courses
=
response
.
data
self
.
assertEqual
(
len
(
courses
),
0
)
self
.
assertEqual
(
len
(
courses
),
0
)
def
test_sort_order
(
self
):
self
.
login
()
num_courses
=
3
courses
=
[]
for
course_num
in
range
(
num_courses
):
courses
.
append
(
CourseFactory
.
create
(
mobile_available
=
True
))
self
.
enroll
(
courses
[
course_num
]
.
id
)
# verify courses are returned in the order of enrollment, with most recently enrolled first.
response
=
self
.
api_response
()
for
course_num
in
range
(
num_courses
):
self
.
assertEqual
(
response
.
data
[
course_num
][
'course'
][
'id'
],
# pylint: disable=no-member
unicode
(
courses
[
num_courses
-
course_num
-
1
]
.
id
)
)
class
CourseStatusAPITestCase
(
MobileAPITestCase
):
class
CourseStatusAPITestCase
(
MobileAPITestCase
):
"""
"""
...
...
lms/djangoapps/mobile_api/users/views.py
View file @
8394fb71
...
@@ -2,9 +2,6 @@
...
@@ -2,9 +2,6 @@
Views for user API
Views for user API
"""
"""
from
courseware.model_data
import
FieldDataCache
from
courseware.module_render
import
get_module_for_descriptor
from
django.shortcuts
import
redirect
from
django.shortcuts
import
redirect
from
django.utils
import
dateparse
from
django.utils
import
dateparse
...
@@ -12,11 +9,13 @@ from rest_framework import generics, views
...
@@ -12,11 +9,13 @@ from rest_framework import generics, views
from
rest_framework.decorators
import
api_view
from
rest_framework.decorators
import
api_view
from
rest_framework.response
import
Response
from
rest_framework.response
import
Response
from
courseware.views
import
get_current_child
,
save_positions_recursively_up
from
opaque_keys.edx.keys
import
UsageKey
from
opaque_keys.edx.keys
import
UsageKey
from
opaque_keys
import
InvalidKeyError
from
opaque_keys
import
InvalidKeyError
from
courseware.access
import
is_mobile_available_for_user
from
courseware.model_data
import
FieldDataCache
from
courseware.module_render
import
get_module_for_descriptor
from
courseware.views
import
get_current_child
,
save_positions_recursively_up
from
student.models
import
CourseEnrollment
,
User
from
student.models
import
CourseEnrollment
,
User
from
xblock.fields
import
Scope
from
xblock.fields
import
Scope
...
@@ -25,8 +24,8 @@ from xmodule.modulestore.django import modulestore
...
@@ -25,8 +24,8 @@ from xmodule.modulestore.django import modulestore
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
.serializers
import
CourseEnrollmentSerializer
,
UserSerializer
from
.serializers
import
CourseEnrollmentSerializer
,
UserSerializer
from
mobile_api
import
errors
from
..
import
errors
from
mobile_api.utils
import
mobile_access_when_enrolled
,
mobile_view
,
mobile_course_access
from
..utils
import
mobile_view
,
mobile_course_access
@mobile_view
(
is_user
=
True
)
@mobile_view
(
is_user
=
True
)
...
@@ -46,6 +45,7 @@ class UserDetail(generics.RetrieveAPIView):
...
@@ -46,6 +45,7 @@ class UserDetail(generics.RetrieveAPIView):
GET /api/mobile/v0.5/users/{username}
GET /api/mobile/v0.5/users/{username}
**Response Values**
**Response Values**
* id: The ID of the user.
* id: The ID of the user.
...
@@ -241,10 +241,13 @@ class UserCourseEnrollmentsList(generics.ListAPIView):
...
@@ -241,10 +241,13 @@ class UserCourseEnrollmentsList(generics.ListAPIView):
lookup_field
=
'username'
lookup_field
=
'username'
def
get_queryset
(
self
):
def
get_queryset
(
self
):
enrollments
=
self
.
queryset
.
filter
(
user__username
=
self
.
kwargs
[
'username'
],
is_active
=
True
)
.
order_by
(
'created'
)
enrollments
=
self
.
queryset
.
filter
(
user__username
=
self
.
kwargs
[
'username'
],
is_active
=
True
)
.
order_by
(
'created'
)
.
reverse
()
return
[
return
[
enrollment
for
enrollment
in
enrollments
enrollment
for
enrollment
in
enrollments
if
mobile_access_when_enrolled
(
enrollment
.
course
,
self
.
request
.
user
)
if
enrollment
.
course
and
is_mobile_available_for_user
(
self
.
request
.
user
,
enrollment
.
course
)
]
]
...
...
lms/djangoapps/mobile_api/utils.py
View file @
8394fb71
...
@@ -4,7 +4,6 @@ Common utility methods and decorators for Mobile APIs.
...
@@ -4,7 +4,6 @@ Common utility methods and decorators for Mobile APIs.
import
functools
import
functools
from
django.http
import
Http404
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys.edx.keys
import
CourseKey
from
courseware.courses
import
get_course_with_access
from
courseware.courses
import
get_course_with_access
...
@@ -37,22 +36,6 @@ def mobile_course_access(depth=0, verify_enrolled=True):
...
@@ -37,22 +36,6 @@ def mobile_course_access(depth=0, verify_enrolled=True):
return
_decorator
return
_decorator
def
mobile_access_when_enrolled
(
course
,
user
):
"""
Determines whether a user has access to a course in a mobile context.
Checks the mobile_available flag and the start_date.
Note: Does not check if the user is actually enrolled in the course.
"""
# The course doesn't always really exist -- we can have bad data in the enrollments
# pointing to non-existent (or removed) courses, in which case `course` is None.
if
not
course
:
return
False
try
:
return
get_course_with_access
(
user
,
'load_mobile_no_enrollment_check'
,
course
.
id
)
is
not
None
except
Http404
:
return
False
def
mobile_view
(
is_user
=
False
):
def
mobile_view
(
is_user
=
False
):
"""
"""
Function and class decorator that abstracts the authentication and permission checks for mobile api views.
Function and class decorator that abstracts the authentication and permission checks for mobile api views.
...
...
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