Skip to content
Snippets Groups Projects
Commit 0fb7c101 authored by jansenk's avatar jansenk
Browse files

Add API call to list roles of the logged-on user

EDUCATOR-3796
parent 14009d3a
No related merge requests found
......@@ -466,6 +466,15 @@ def unenroll_user_from_all_courses(user_id):
return _data_api().unenroll_user_from_all_courses(user_id)
def get_user_roles(user_id):
"""
Returns a list of all roles that this user has.
:param user_id: The id of the selected user.
:return: All roles for all courses that this user has.
"""
return _data_api().get_user_roles(user_id)
def _data_api():
"""Returns a Data API.
This relies on Django settings to find the appropriate data API.
......
......@@ -27,6 +27,7 @@ from student.models import (
EnrollmentClosedError,
NonExistentCourseError
)
from student.roles import RoleCache
log = logging.getLogger(__name__)
......@@ -337,3 +338,16 @@ def get_course_enrollment_info(course_id, include_expired=False):
raise CourseNotFoundError(msg)
else:
return CourseSerializer(course, include_expired=include_expired).data
def get_user_roles(user_id):
"""
Returns a list of all roles that this user has.
:param user_id: The id of the selected user.
:return: All roles for all courses that this user has.
"""
user = _get_user(user_id)
if not hasattr(user, '_roles'):
user._roles = RoleCache(user)
role_cache = user._roles
return role_cache._roles
......@@ -23,7 +23,7 @@ from enrollment.errors import (
from enrollment.serializers import CourseEnrollmentSerializer
from openedx.core.lib.exceptions import CourseNotFoundError
from student.models import AlreadyEnrolledError, CourseEnrollment, CourseFullError, EnrollmentClosedError
from student.tests.factories import UserFactory
from student.tests.factories import UserFactory, CourseAccessRoleFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
......@@ -378,3 +378,19 @@ class EnrollmentDataTest(ModuleStoreTestCase):
if not include_expired:
self.assertNotIn('verified', result_slugs)
def test_get_roles(self):
"""Create a role for a user, then get it"""
expected_role = CourseAccessRoleFactory.create(course_id=self.course.id, user=self.user, role="SuperCoolTestRole")
roles = data.get_user_roles(self.user.username)
self.assertEqual(roles, {expected_role})
def test_get_roles_no_roles(self):
"""Get roles for a user who has no roles"""
roles = data.get_user_roles(self.user.username)
self.assertEqual(roles, set())
def test_get_roles_invalid_user(self):
"""Get roles for a user that doesn't exist"""
with pytest.raises(UserNotFoundError):
data.get_user_roles("i_dont_exist_and_should_raise_an_error")
......@@ -45,6 +45,7 @@ from student.roles import CourseStaffRole
from student.tests.factories import AdminFactory, UserFactory, SuperuserFactory
from util.models import RateLimitConfiguration
from util.testing import UrlResetMixin
from six import text_type
class EnrollmentTestMixin(object):
......@@ -1413,3 +1414,72 @@ class UnenrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase):
url = reverse('unenrollment')
headers = self.build_jwt_headers(submitting_user)
return self.client.post(url, json.dumps(data), content_type='application/json', **headers)
@ddt.ddt
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class UserRoleTest(ModuleStoreTestCase):
"""
Tests the API call to list user roles.
"""
USERNAME = "Bob"
EMAIL = "bob@example.com"
PASSWORD = "edx"
ENABLED_CACHES = ['default']
def setUp(self):
""" Create a course and user, then log in. """
super(UserRoleTest, self).setUp()
self.course1 = CourseFactory.create(emit_signals=True, org="org1", course="course1", run="run1")
self.course2 = CourseFactory.create(emit_signals=True, org="org2", course="course2", run="run2")
self.user = UserFactory.create(
username=self.USERNAME,
email=self.EMAIL,
password=self.PASSWORD,
)
self.client.login(username=self.USERNAME, password=self.PASSWORD)
def _create_expected_role_dict(self, course, role):
return {
'course_id': text_type(course.id),
'org': course.org,
'role': role.ROLE,
}
def _assert_roles(self, expected_response):
response = self.client.get(reverse('roles'))
self.assertEqual(response.status_code, status.HTTP_200_OK)
response_data = json.loads(response.content)
self.assertEqual(response_data, expected_response)
def test_not_logged_in(self):
self.client.logout()
response = self.client.get(reverse('roles'))
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
def test_roles_no_roles(self):
self._assert_roles([])
def test_roles(self):
role1 = CourseStaffRole(self.course1.id)
role1.add_users(self.user)
expected_role1 = self._create_expected_role_dict(self.course1, role1)
self._assert_roles([expected_role1])
role2 = CourseStaffRole(self.course2.id)
role2.add_users(self.user)
expected_role2 = self._create_expected_role_dict(self.course2, role2)
self._assert_roles([expected_role2, expected_role1])
def test_roles_exception(self):
with patch('enrollment.api.get_user_roles') as mock_get_user_roles:
mock_get_user_roles.side_effect = Exception()
response = self.client.get(reverse('roles'))
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
expected_response = {
"message": (
u"An error occurred while retrieving roles for user '{username}"
).format(username=self.user.username)
}
response_data = json.loads(response.content)
self.assertEqual(response_data, expected_response)
......@@ -5,7 +5,7 @@ URLs for the Enrollment API
from django.conf import settings
from django.conf.urls import url
from .views import EnrollmentCourseDetailView, EnrollmentListView, EnrollmentView, UnenrollmentView
from .views import EnrollmentCourseDetailView, EnrollmentListView, EnrollmentView, UnenrollmentView, EnrollmentUserRolesView
urlpatterns = [
url(r'^enrollment/{username},{course_key}$'.format(
......@@ -18,4 +18,5 @@ urlpatterns = [
url(r'^course/{course_key}$'.format(course_key=settings.COURSE_ID_PATTERN),
EnrollmentCourseDetailView.as_view(), name='courseenrollmentdetails'),
url(r'^unenroll/$', UnenrollmentView.as_view(), name='unenrollment'),
url(r'^roles/$', EnrollmentUserRolesView.as_view(), name='roles'),
]
......@@ -205,6 +205,55 @@ class EnrollmentView(APIView, ApiKeyPermissionMixIn):
)
class EnrollmentUserRolesView(APIView):
"""
**Use Case**
Get the roles for the current logged-in user.
**Example Requests**
GET /api/enrollment/v1/roles/
**Response Values**
If the request is successful, an HTTP 200 "OK" response is
returned along with a collection of user roles for the
logged-in user
"""
authentication_classes = (JwtAuthentication,
OAuth2AuthenticationAllowInactiveUser,
EnrollmentCrossDomainSessionAuth)
permission_classes = ApiKeyHeaderPermissionIsAuthenticated,
throttle_classes = EnrollmentUserThrottle,
@method_decorator(ensure_csrf_cookie_cross_domain)
def get(self, request):
"""
Gets a list of all roles for the currently logged-in user
"""
try:
roles_data = api.get_user_roles(request.user.username)
except Exception:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={
"message": (
u"An error occurred while retrieving roles for user '{username}"
).format(username=request.user.username)
}
)
return Response([
{
"org": role.org,
"course_id": text_type(role.course_id),
"role": role.role
}
for role in roles_data
])
@can_disable_rate_limit
class EnrollmentCourseDetailView(APIView):
"""
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment