Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cms/djangoapps/auth/authz.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,14 @@ def is_user_in_creator_group(user):
return user.groups.filter(name=COURSE_CREATOR_GROUP_NAME).count() > 0

return True


def _grant_instructors_creator_access(caller):
"""
This is to be called only by either a command line code path or through an app which has already
asserted permissions to do this action

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should document that this is to grandfather in existing instructors. Ideally this will only be run once, ever.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will update it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or perhaps I should just add a task to delete this code (and the django command) at the end of this story?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although perhaps we will want to run it on edx at some point. Hmmmmm.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, this kinda feels like a "Migration", but without a schema change. I don't know much about those tools to make a recommendation, maybe Dave O or Victor might have a suggestion.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All add a task to the story to delete the code if appropriate.

"""
for group in Group.objects.all():
if group.name.startswith(INSTRUCTOR_ROLE_NAME + "_"):
for user in group.user_set.all():
add_user_to_creator_group(caller, user)
42 changes: 41 additions & 1 deletion cms/djangoapps/auth/tests/test_authz.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from auth.authz import add_user_to_creator_group, remove_user_from_creator_group, is_user_in_creator_group,\
create_all_course_groups, add_user_to_course_group, STAFF_ROLE_NAME, INSTRUCTOR_ROLE_NAME,\
is_user_in_course_group_role, remove_user_from_course_group
is_user_in_course_group_role, remove_user_from_course_group, _grant_instructors_creator_access


class CreatorGroupTest(TestCase):
Expand Down Expand Up @@ -174,3 +174,43 @@ def test_remove_user_from_course_group_permission_denied(self):
create_all_course_groups(self.creator, self.location)
with self.assertRaises(PermissionDenied):
remove_user_from_course_group(self.staff, self.staff, self.location, STAFF_ROLE_NAME)


class GrantInstructorsCreatorAccessTest(TestCase):
"""
Tests granting existing instructors course creator rights.
"""
def create_course(self, index):
"""
Creates a course with one instructor and one staff member.
"""
creator = User.objects.create_user('testcreator'+str(index), 'testcreator+courses@edx.org', 'foo')
staff = User.objects.create_user('teststaff'+str(index), 'teststaff+courses@edx.org', 'foo')
location = 'i4x', 'mitX', str(index), 'course', 'test'
create_all_course_groups(creator, location)
add_user_to_course_group(creator, staff, location, STAFF_ROLE_NAME)
return [creator, staff]

def test_grant_creator_access(self):
"""
Test for _grant_instructors_creator_access.
"""
[creator1, staff1] = self.create_course(1)
[creator2, staff2] = self.create_course(2)
with mock.patch.dict('django.conf.settings.MITX_FEATURES', {"ENABLE_CREATOR_GROUP": True}):
# Initially no creators.
self.assertFalse(is_user_in_creator_group(creator1))
self.assertFalse(is_user_in_creator_group(creator2))
self.assertFalse(is_user_in_creator_group(staff1))
self.assertFalse(is_user_in_creator_group(staff2))

admin = User.objects.create_user('populate_creators_command', 'grant+creator+access@edx.org', 'foo')
admin.is_staff = True
_grant_instructors_creator_access(admin)

# Now instructors only are creators.
self.assertTrue(is_user_in_creator_group(creator1))
self.assertTrue(is_user_in_creator_group(creator2))
self.assertFalse(is_user_in_creator_group(staff1))
self.assertFalse(is_user_in_creator_group(staff2))

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
Script for granting existing course instructors course creator privileges.
"""
from auth.authz import _grant_instructors_creator_access
from django.core.management.base import BaseCommand

from django.contrib.auth.models import User
from django.db.utils import IntegrityError


class Command(BaseCommand):
"""
Script for granting existing course instructors course creator privileges.
"""
help = 'Grants all users with INSTRUCTOR role permission to create courses'

def handle(self, *args, **options):
"""
The logic of the command.
"""
username = 'populate_creators_command'
email = 'grant+creator+access@edx.org'
try:
admin = User.objects.create_user(username, email, 'foo')
admin.is_staff = True
admin.save()
except IntegrityError:
# If the script did not complete the last time it was run,
# the admin user will already exist.
admin = User.objects.get(username=username, email=email)

_grant_instructors_creator_access(admin)
admin.delete()