diff --git a/common/djangoapps/student/admin.py b/common/djangoapps/student/admin.py index d85621287e..6114878177 100644 --- a/common/djangoapps/student/admin.py +++ b/common/djangoapps/student/admin.py @@ -3,6 +3,7 @@ django admin pages for courseware model ''' from django import forms from config_models.admin import ConfigurationModelAdmin +from django.contrib.auth.models import User from student.models import UserProfile, UserTestGroup, CourseEnrollmentAllowed, DashboardConfiguration from student.models import ( @@ -11,24 +12,113 @@ from student.models import ( from ratelimitbackend import admin from student.roles import REGISTERED_ACCESS_ROLES +from xmodule.modulestore.django import modulestore + +from opaque_keys.edx.keys import CourseKey +from opaque_keys import InvalidKeyError + class CourseAccessRoleForm(forms.ModelForm): """Form for adding new Course Access Roles view the Django Admin Panel.""" class Meta: model = CourseAccessRole + email = forms.EmailField(required=True) COURSE_ACCESS_ROLES = [(role_name, role_name) for role_name in REGISTERED_ACCESS_ROLES.keys()] role = forms.ChoiceField(choices=COURSE_ACCESS_ROLES) + def clean_course_id(self): + """ + Checking course-id format and course exists in module store. + This field can be null. + """ + if self.cleaned_data['course_id']: + course_id = self.cleaned_data['course_id'] + + try: + course_key = CourseKey.from_string(course_id) + except InvalidKeyError: + raise forms.ValidationError(u"Cannot make a valid CourseKey from id {}!".format(course_id)) + + if not modulestore().has_course(course_key): + raise forms.ValidationError(u"Cannot find course with id {} in the modulestore".format(course_id)) + + return course_key + + return None + + def clean_org(self): + """If org and course-id exists then Check organization name + against the given course. + """ + if self.cleaned_data.get('course_id') and self.cleaned_data['org']: + org = self.cleaned_data['org'] + org_name = self.cleaned_data.get('course_id').org + if org.lower() != org_name.lower(): + raise forms.ValidationError( + u"Org name {} is not valid. Valid name is {}.".format( + org, org_name + ) + ) + + return self.cleaned_data['org'] + + def clean_email(self): + """ + Checking user object against given email id. + """ + email = self.cleaned_data['email'] + try: + user = User.objects.get(email=email) + except Exception: + raise forms.ValidationError( + u"Email not exists. Could not find user by email address {email}.".format( + email=email + ) + ) + + return user + + def clean(self): + """ + Checking the course already exists in db. + """ + cleaned_data = super(CourseAccessRoleForm, self).clean() + if not self.errors: + if CourseAccessRole.objects.filter( + user=cleaned_data.get("email"), + org=cleaned_data.get("org"), + course_id=cleaned_data.get("course_id"), + role=cleaned_data.get("role") + ).exists(): + raise forms.ValidationError("Duplicate Record.") + + return cleaned_data + class CourseAccessRoleAdmin(admin.ModelAdmin): """Admin panel for the Course Access Role. """ form = CourseAccessRoleForm raw_id_fields = ("user",) - list_display = ( - 'id', 'user', 'org', 'course_id', 'role' + exclude = ("user",) + + fieldsets = ( + (None, { + 'fields': ('email', 'course_id', 'org', 'role',) + }), ) + list_display = ( + 'id', 'user', 'org', 'course_id', 'role', + ) + search_fields = ( + 'id', 'user__username', 'user__email', 'org', 'course_id', 'role', + ) + + def save_model(self, request, obj, form, change): + obj.user = form.cleaned_data['email'] + super(CourseAccessRoleAdmin, self).save_model(request, obj, form, change) + class LinkedInAddToProfileConfigurationAdmin(admin.ModelAdmin): """Admin interface for the LinkedIn Add to Profile configuration. """ diff --git a/common/djangoapps/student/tests/test_admin_views.py b/common/djangoapps/student/tests/test_admin_views.py new file mode 100644 index 0000000000..c6998b74b0 --- /dev/null +++ b/common/djangoapps/student/tests/test_admin_views.py @@ -0,0 +1,148 @@ +""" +Tests student admin.py +""" +from django.core.urlresolvers import reverse + +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory +from student.tests.factories import UserFactory + + +class AdminCourseRolesPageTest(ModuleStoreTestCase): + """Test the django admin course roles form saving data in db. + """ + def setUp(self): + super(AdminCourseRolesPageTest, self).setUp() + self.user = UserFactory.create(is_staff=True, is_superuser=True) + self.user.save() + self.course = CourseFactory.create(org='edx') + + def test_save_valid_data(self): + + data = { + 'course_id': unicode(self.course.id), + 'role': 'finance_admin', + 'org': 'edx', + 'email': self.user.email + } + + self.client.login(username=self.user.username, password='test') + + # # adding new role from django admin page + response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data) + self.assertRedirects(response, reverse('admin:student_courseaccessrole_changelist')) + + response = self.client.get(reverse('admin:student_courseaccessrole_changelist')) + self.assertContains(response, 'Select course access role to change') + self.assertContains(response, 'Add course access role') + self.assertContains(response, 'finance_admin') + self.assertContains(response, unicode(self.course.id)) + self.assertContains(response, '1 course access role') + + #try adding with same information raise error. + response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data) + self.assertContains(response, 'Duplicate') + + def test_save_without_org_and_course_data(self): + + data = { + 'role': 'staff', + 'email': self.user.email, + 'course_id': unicode(self.course.id) + } + + self.client.login(username=self.user.username, password='test') + + # # adding new role from django admin page + response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data) + self.assertRedirects(response, reverse('admin:student_courseaccessrole_changelist')) + + response = self.client.get(reverse('admin:student_courseaccessrole_changelist')) + self.assertContains(response, 'staff') + self.assertContains(response, '1 course access role') + + def test_save_with_course_only(self): + + data = { + 'role': 'beta_testers', + 'email': self.user.email, + + } + + self.client.login(username=self.user.username, password='test') + + # # adding new role from django admin page + response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data) + self.assertRedirects(response, reverse('admin:student_courseaccessrole_changelist')) + + response = self.client.get(reverse('admin:student_courseaccessrole_changelist')) + self.assertContains(response, 'beta_testers') + self.assertContains(response, '1 course access role') + + def test_save_with_org_only(self): + + data = { + 'role': 'beta_testers', + 'email': self.user.email, + 'org': 'myorg' + + } + + self.client.login(username=self.user.username, password='test') + + # # adding new role from django admin page + response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data) + self.assertRedirects(response, reverse('admin:student_courseaccessrole_changelist')) + + response = self.client.get(reverse('admin:student_courseaccessrole_changelist')) + self.assertContains(response, 'myorg') + self.assertContains(response, '1 course access role') + + def test_save_with_invalid_course(self): + + course = unicode('no/edx/course') + email = "invalid@email.com" + data = { + 'course_id': course, + 'role': 'finance_admin', + 'org': 'edx', + 'email': email + } + + self.client.login(username=self.user.username, password='test') + + # Adding new role with invalid data + response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data) + self.assertContains( + response, + 'Cannot find course with id {} in the modulestore'.format( + course + ) + ) + + self.assertContains( + response, + "Email not exists. Could not find user by email address {}".format( + email + ) + ) + + def test_save_valid_course_invalid_org(self): + + data = { + 'course_id': unicode(self.course.id), + 'role': 'finance_admin', + 'org': 'edxxx', + 'email': self.user.email + } + + self.client.login(username=self.user.username, password='test') + + # # adding new role from django admin page + response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data) + self.assertContains( + response, + 'Org name {} is not valid. Valid name is {}.'.format( + 'edxxx', 'edx' + ) + )