Merge pull request #14074 from edx/TNL-6015
Remove access for inactive users
This commit is contained in:
@@ -147,13 +147,6 @@ def _course_team_user(request, course_key, email):
|
||||
if not ((requester_perms & STUDIO_EDIT_ROLES) or (user.id == request.user.id)):
|
||||
return permissions_error_response
|
||||
|
||||
# can't modify an inactive user
|
||||
if not user.is_active:
|
||||
msg = {
|
||||
"error": _('User {email} has registered but has not yet activated his/her account.').format(email=email),
|
||||
}
|
||||
return JsonResponse(msg, 400)
|
||||
|
||||
if request.method == "DELETE":
|
||||
new_role = None
|
||||
else:
|
||||
@@ -165,6 +158,13 @@ def _course_team_user(request, course_key, email):
|
||||
else:
|
||||
return JsonResponse({"error": _("No `role` specified.")}, 400)
|
||||
|
||||
# can't modify an inactive user but can remove it
|
||||
if not (user.is_active or new_role is None):
|
||||
msg = {
|
||||
"error": _('User {email} has registered but has not yet activated his/her account.').format(email=email),
|
||||
}
|
||||
return JsonResponse(msg, 400)
|
||||
|
||||
old_roles = set()
|
||||
role_added = False
|
||||
for role_type in role_hierarchy:
|
||||
@@ -177,7 +177,7 @@ def _course_team_user(request, course_key, email):
|
||||
role_added = True
|
||||
else:
|
||||
return permissions_error_response
|
||||
elif role.has_user(user):
|
||||
elif role.has_user(user, check_user_activation=False):
|
||||
# Remove the user from this old role:
|
||||
old_roles.add(role)
|
||||
|
||||
|
||||
@@ -130,11 +130,19 @@ class RoleBase(AccessRole):
|
||||
self.course_key = course_key
|
||||
self._role_name = role_name
|
||||
|
||||
def has_user(self, user):
|
||||
# pylint: disable=arguments-differ
|
||||
def has_user(self, user, check_user_activation=True):
|
||||
"""
|
||||
Return whether the supplied django user has access to this role.
|
||||
Check if the supplied django user has access to this role.
|
||||
|
||||
Arguments:
|
||||
user: user to check against access to role
|
||||
check_user_activation: Indicating whether or not we need to check
|
||||
user activation while checking user roles
|
||||
Return:
|
||||
bool identifying if user has that particular role or not
|
||||
"""
|
||||
if not (user.is_authenticated() and user.is_active):
|
||||
if check_user_activation and not (user.is_authenticated() and user.is_active):
|
||||
return False
|
||||
|
||||
# pylint: disable=protected-access
|
||||
|
||||
@@ -2001,6 +2001,7 @@ def auto_auth(request):
|
||||
* `redirect`: Set to "true" will redirect to the `redirect_to` value if set, or
|
||||
course home page if course_id is defined, otherwise it will redirect to dashboard
|
||||
* `redirect_to`: will redirect to to this url
|
||||
* `is_active` : make/update account with status provided as 'is_active'
|
||||
If username, email, or password are not provided, use
|
||||
randomly generated credentials.
|
||||
"""
|
||||
@@ -2017,10 +2018,13 @@ def auto_auth(request):
|
||||
is_superuser = request.GET.get('superuser', None)
|
||||
course_id = request.GET.get('course_id', None)
|
||||
redirect_to = request.GET.get('redirect_to', None)
|
||||
active_status = request.GET.get('is_active')
|
||||
|
||||
# mode has to be one of 'honor'/'professional'/'verified'/'audit'/'no-id-professional'/'credit'
|
||||
enrollment_mode = request.GET.get('enrollment_mode', 'honor')
|
||||
|
||||
active_status = (not active_status or active_status == 'true')
|
||||
|
||||
course_key = None
|
||||
if course_id:
|
||||
course_key = CourseLocator.from_string(course_id)
|
||||
@@ -2048,6 +2052,7 @@ def auto_auth(request):
|
||||
user = User.objects.get(username=username)
|
||||
user.email = email
|
||||
user.set_password(password)
|
||||
user.is_active = active_status
|
||||
user.save()
|
||||
profile = UserProfile.objects.get(user=user)
|
||||
reg = Registration.objects.get(user=user)
|
||||
@@ -2061,9 +2066,9 @@ def auto_auth(request):
|
||||
user.is_superuser = (is_superuser == "true")
|
||||
user.save()
|
||||
|
||||
# Activate the user
|
||||
reg.activate()
|
||||
reg.save()
|
||||
if active_status:
|
||||
reg.activate()
|
||||
reg.save()
|
||||
|
||||
# ensure parental consent threshold is met
|
||||
year = datetime.date.today().year
|
||||
|
||||
@@ -12,19 +12,24 @@ class AutoAuthPage(PageObject):
|
||||
"""
|
||||
The automatic authorization page.
|
||||
When allowed via the django settings file, visiting
|
||||
this url will create a user and log them in.
|
||||
this url will create/update a user and log them in.
|
||||
"""
|
||||
|
||||
def __init__(self, browser, username=None, email=None, password=None,
|
||||
staff=None, course_id=None, roles=None, no_login=None):
|
||||
staff=None, course_id=None, roles=None, no_login=None, is_active=None):
|
||||
"""
|
||||
Auto-auth is an end-point for HTTP GET requests.
|
||||
By default, it will create accounts with random user credentials,
|
||||
but you can also specify credentials using querystring parameters.
|
||||
|
||||
Can be used to update an account, call to this end-point with already
|
||||
made account's credentials along with values to update will result into
|
||||
an account update.
|
||||
|
||||
`username`, `email`, and `password` are the user's credentials (strings)
|
||||
`staff` is a boolean indicating whether the user is global staff.
|
||||
`course_id` is the ID of the course to enroll the student in.
|
||||
`is_active` activation status of user
|
||||
Currently, this has the form "org/number/run"
|
||||
|
||||
Note that "global staff" is NOT the same as course staff.
|
||||
@@ -55,6 +60,9 @@ class AutoAuthPage(PageObject):
|
||||
if no_login:
|
||||
self._params['no_login'] = True
|
||||
|
||||
if is_active is not None:
|
||||
self._params['is_active'] = 'true' if is_active else 'false'
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
"""
|
||||
|
||||
@@ -26,6 +26,17 @@ class CourseTeamPageTest(StudioCourseTest):
|
||||
).visit()
|
||||
return user
|
||||
|
||||
def _update_user(self, user_info):
|
||||
"""
|
||||
Update user with provided `user_info`
|
||||
|
||||
Arguments:
|
||||
`user_info`: dictionary containing values of attributes to be updated
|
||||
"""
|
||||
AutoAuthPage(
|
||||
self.browser, no_login=True, **user_info
|
||||
).visit()
|
||||
|
||||
def setUp(self, is_staff=False):
|
||||
"""
|
||||
Install a course with no content using a fixture.
|
||||
@@ -174,6 +185,34 @@ class CourseTeamPageTest(StudioCourseTest):
|
||||
self.log_in(self.other_user)
|
||||
self._assert_current_course(visible=False)
|
||||
|
||||
def test_admins_can_delete_other_inactive_users(self):
|
||||
"""
|
||||
Scenario: Admins can delete other inactive users
|
||||
Given I have opened a new course in Studio
|
||||
And I am viewing the course team settings.
|
||||
When I add other user to the course team,
|
||||
And then delete that other user from the course team.
|
||||
And other user logs in
|
||||
Then he/she does not see the course on page
|
||||
"""
|
||||
self.page.add_user_to_course(self.other_user.get('email'))
|
||||
self._assert_user_present(self.other_user, present=True)
|
||||
|
||||
# inactivate user
|
||||
user_info = {
|
||||
'username': self.other_user.get('username'),
|
||||
'email': self.other_user.get('email'),
|
||||
'password': self.other_user.get('password'),
|
||||
'is_active': False
|
||||
}
|
||||
self._update_user(user_info)
|
||||
|
||||
# go to course team page to perform delete operation
|
||||
self._go_to_course_team_page()
|
||||
self.page.delete_user_from_course(self.other_user.get('email'))
|
||||
|
||||
self._assert_user_present(self.other_user, present=False)
|
||||
|
||||
def test_admins_cannot_add_users_that_do_not_exist(self):
|
||||
"""
|
||||
Scenario: Admins cannot add users that do not exist
|
||||
|
||||
Reference in New Issue
Block a user