def test_update_creator_group(self):
     with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
         self.assertFalse(auth.user_has_role(self.user, CourseCreatorRole()))
         update_course_creator_group(self.admin, self.user, True)
         self.assertTrue(auth.user_has_role(self.user, CourseCreatorRole()))
         update_course_creator_group(self.admin, self.user, False)
         self.assertFalse(auth.user_has_role(self.user, CourseCreatorRole()))
Beispiel #2
0
 def test_update_org_role_permission(self):
     """
     Verifies if caller of update_org_role is GlobalAdmin.
     """
     assert not user_has_role(self.user, OrgContentCreatorRole(self.org))
     update_org_role(self.global_admin, OrgContentCreatorRole, self.user,
                     [self.org])
     assert user_has_role(self.user, OrgContentCreatorRole(self.org))
Beispiel #3
0
    def test_creator_group_enabled_but_empty(self):
        """ Tests creator group feature on, but group empty. """
        with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
            self.assertFalse(user_has_role(self.user, CourseCreatorRole()))

            # Make user staff. This will cause CourseCreatorRole().has_user to return True.
            self.user.is_staff = True
            self.assertTrue(user_has_role(self.user, CourseCreatorRole()))
Beispiel #4
0
def is_content_creator(user, org):
    """
    Check if the user has the role to create content.

    This function checks if the User has role to create content
    or if the org is supplied, it checks for Org level course content
    creator.
    """
    return (auth.user_has_role(user, CourseCreatorRole()) or
            auth.user_has_role(user, OrgContentCreatorRole(org=org)))
Beispiel #5
0
 def test_update_org_content_creator_role(self):
     with mock.patch.dict('django.conf.settings.FEATURES',
                          {"ENABLE_CREATOR_GROUP": True}):
         self.assertFalse(
             auth.user_has_role(self.user, OrgContentCreatorRole(self.org)))
         update_org_content_creator_role(self.admin, self.user, [self.org])
         self.assertTrue(
             auth.user_has_role(self.user, OrgContentCreatorRole(self.org)))
         update_org_content_creator_role(self.admin, self.user, [])
         self.assertFalse(
             auth.user_has_role(self.user, OrgContentCreatorRole(self.org)))
Beispiel #6
0
 def test_detail_post(self):
     resp = self.client.post(
         self.detail_url,
         data={"role": ""},
     )
     self.assertEqual(resp.status_code, 204)
     # reload user from DB
     ext_user = User.objects.get(email=self.ext_user.email)
     # no content: should not be in any roles
     self.assertFalse(auth.user_has_role(ext_user, CourseStaffRole(self.course.id)))
     self.assertFalse(auth.user_has_role(ext_user, CourseInstructorRole(self.course.id)))
     self.assert_not_enrolled()
Beispiel #7
0
 def test_detail_post_no_json(self):
     resp = self.client.post(
         self.detail_url,
         data={"role": "staff"},
         HTTP_ACCEPT="application/json",
     )
     self.assertEqual(resp.status_code, 204)
     # reload user from DB
     ext_user = User.objects.get(email=self.ext_user.email)
     self.assertTrue(auth.user_has_role(ext_user, CourseStaffRole(self.course.id)))
     self.assertFalse(auth.user_has_role(ext_user, CourseInstructorRole(self.course.id)))
     self.assert_enrolled()
Beispiel #8
0
    def test_creator_group_enabled_nonempty(self):
        """ Tests creator group feature on, user added. """
        with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
            add_users(self.admin, CourseCreatorRole(), self.user)
            self.assertTrue(user_has_role(self.user, CourseCreatorRole()))

            # check that a user who has not been added to the group still returns false
            user_not_added = User.objects.create_user('testuser2', '*****@*****.**', 'foo2')
            self.assertFalse(user_has_role(user_not_added, CourseCreatorRole()))

            # remove first user from the group and verify that CourseCreatorRole().has_user now returns false
            remove_users(self.admin, CourseCreatorRole(), self.user)
            self.assertFalse(user_has_role(self.user, CourseCreatorRole()))
    def test_add_granted(self):
        with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
            # Calling add_user_with_status_granted impacts is_user_in_course_group_role.
            self.assertFalse(auth.user_has_role(self.user, CourseCreatorRole()))

            add_user_with_status_granted(self.admin, self.user)
            self.assertEqual('granted', get_course_creator_status(self.user))

            # Calling add again will be a no-op (even if state is different).
            add_user_with_status_unrequested(self.user)
            self.assertEqual('granted', get_course_creator_status(self.user))

            self.assertTrue(auth.user_has_role(self.user, CourseCreatorRole()))
Beispiel #10
0
    def test_add_user_to_course_group(self):
        """
        Tests adding user to course group (happy path).
        """
        # Create groups for a new course (and assign instructor role to the creator).
        self.assertFalse(user_has_role(self.creator, CourseInstructorRole(self.course_key)))
        add_users(self.global_admin, CourseInstructorRole(self.course_key), self.creator)
        add_users(self.global_admin, CourseStaffRole(self.course_key), self.creator)
        self.assertTrue(user_has_role(self.creator, CourseInstructorRole(self.course_key)))

        # Add another user to the staff role.
        self.assertFalse(user_has_role(self.staff, CourseStaffRole(self.course_key)))
        add_users(self.creator, CourseStaffRole(self.course_key), self.staff)
        self.assertTrue(user_has_role(self.staff, CourseStaffRole(self.course_key)))
Beispiel #11
0
    def test_remove_user_from_course_group(self):
        """
        Tests removing user from course group (happy path).
        """
        add_users(self.global_admin, CourseInstructorRole(self.course_key), self.creator)
        add_users(self.global_admin, CourseStaffRole(self.course_key), self.creator)

        add_users(self.creator, CourseStaffRole(self.course_key), self.staff)
        self.assertTrue(user_has_role(self.staff, CourseStaffRole(self.course_key)))

        remove_users(self.creator, CourseStaffRole(self.course_key), self.staff)
        self.assertFalse(user_has_role(self.staff, CourseStaffRole(self.course_key)))

        remove_users(self.creator, CourseInstructorRole(self.course_key), self.creator)
        self.assertFalse(user_has_role(self.creator, CourseInstructorRole(self.course_key)))
Beispiel #12
0
 def is_course_staff(self, user, course_id):
     """
     Returns True if the user is the course staff
     else Returns False
     """
     return auth.user_has_role(
         user, CourseStaffRole(CourseKey.from_string(course_id)))
Beispiel #13
0
def is_user_course_or_global_staff(user, course_id):
    """
    Return whether a user is course staff for a given course, described by the course_id,
    or is global staff.
    """

    return user.is_staff or auth.user_has_role(
        user, CourseStaffRole(CourseKey.from_string(course_id)))
Beispiel #14
0
    def test_course_creation_disabled(self):
        """ Tests that the COURSE_CREATION_DISABLED flag overrides course creator group settings. """
        with mock.patch.dict('django.conf.settings.FEATURES',
                             {'DISABLE_COURSE_CREATION': True, "ENABLE_CREATOR_GROUP": True}):
            # Add user to creator group.
            add_users(self.admin, CourseCreatorRole(), self.user)

            # DISABLE_COURSE_CREATION overrides (user is not marked as staff).
            self.assertFalse(user_has_role(self.user, CourseCreatorRole()))

            # Mark as staff. Now CourseCreatorRole().has_user returns true.
            self.user.is_staff = True
            self.assertTrue(user_has_role(self.user, CourseCreatorRole()))

            # Remove user from creator group. CourseCreatorRole().has_user still returns true because is_staff=True
            remove_users(self.admin, CourseCreatorRole(), self.user)
            self.assertTrue(user_has_role(self.user, CourseCreatorRole()))
Beispiel #15
0
    def test_detail_post_staff_other_inst(self):
        auth.add_users(self.user, CourseInstructorRole(self.course.id), self.user)

        resp = self.client.post(
            self.detail_url,
            data=json.dumps({"role": "staff"}),
            content_type="application/json",
            HTTP_ACCEPT="application/json",
        )
        self.assertEqual(resp.status_code, 204)
        # reload user from DB
        ext_user = User.objects.get(email=self.ext_user.email)
        self.assertTrue(auth.user_has_role(ext_user, CourseStaffRole(self.course.id)))
        self.assertFalse(auth.user_has_role(ext_user, CourseInstructorRole(self.course.id)))
        self.assert_enrolled()
        # check that other user is unchanged
        user = User.objects.get(email=self.user.email)
        self.assertTrue(auth.user_has_role(user, CourseInstructorRole(self.course.id)))
        self.assertFalse(CourseStaffRole(self.course.id).has_user(user))
Beispiel #16
0
    def test_detail_delete_instructor(self):
        auth.add_users(self.user, CourseInstructorRole(self.course.id), self.ext_user, self.user)

        resp = self.client.delete(
            self.detail_url,
            HTTP_ACCEPT="application/json",
        )
        self.assertEqual(resp.status_code, 204)
        # reload user from DB
        ext_user = User.objects.get(email=self.ext_user.email)
        self.assertFalse(auth.user_has_role(ext_user, CourseInstructorRole(self.course.id)))
Beispiel #17
0
 def test_add_user_not_active(self):
     """
     Tests that adding to creator group fails if user is not active
     """
     with mock.patch.dict('django.conf.settings.FEATURES', {
             'DISABLE_COURSE_CREATION': False,
             "ENABLE_CREATOR_GROUP": True
     }):
         self.user.is_active = False
         add_users(self.admin, CourseCreatorRole(), self.user)
         assert not user_has_role(self.user, CourseCreatorRole())
Beispiel #18
0
    def test_staff_cannot_delete_other(self):
        auth.add_users(self.user, CourseStaffRole(self.course.id), self.user, self.ext_user)
        self.user.is_staff = False
        self.user.save()

        resp = self.client.delete(self.detail_url)
        self.assertEqual(resp.status_code, 403)
        result = json.loads(resp.content.decode('utf-8'))
        self.assertIn("error", result)
        # reload user from DB
        ext_user = User.objects.get(email=self.ext_user.email)
        self.assertTrue(auth.user_has_role(ext_user, CourseStaffRole(self.course.id)))
Beispiel #19
0
    def test_staff_can_delete_self(self):
        auth.add_users(self.user, CourseStaffRole(self.course.id), self.user)
        self.user.is_staff = False
        self.user.save()

        self_url = self.course_team_url(email=self.user.email)

        resp = self.client.delete(self_url)
        self.assertEqual(resp.status_code, 204)
        # reload user from DB
        user = User.objects.get(email=self.user.email)
        self.assertFalse(auth.user_has_role(user, CourseStaffRole(self.course.id)))
Beispiel #20
0
def is_mobile_available_for_user(user, descriptor):
    """
    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
    Arguments:
        descriptor (CourseBlock|CourseOverview): course or overview of course in question
    """
    return (auth.user_has_role(user, CourseBetaTesterRole(descriptor.id))
            or _has_staff_access_to_descriptor(user, descriptor, descriptor.id)
            or _is_descriptor_mobile_available(descriptor))
Beispiel #21
0
 def test_add_user_not_authenticated(self):
     """
     Tests that adding to creator group fails if user is not authenticated
     """
     with mock.patch.dict('django.conf.settings.FEATURES', {
             'DISABLE_COURSE_CREATION': False,
             "ENABLE_CREATOR_GROUP": True
     }):
         anonymous_user = AnonymousUser()
         role = CourseCreatorRole()
         add_users(self.admin, role, anonymous_user)
         assert not user_has_role(anonymous_user, role)
Beispiel #22
0
    def test_delete_last_instructor(self):
        auth.add_users(self.user, CourseInstructorRole(self.course.id), self.ext_user)

        resp = self.client.delete(
            self.detail_url,
            HTTP_ACCEPT="application/json",
        )
        self.assertEqual(resp.status_code, 400)
        result = json.loads(resp.content.decode('utf-8'))
        self.assertIn("error", result)
        # reload user from DB
        ext_user = User.objects.get(email=self.ext_user.email)
        self.assertTrue(auth.user_has_role(ext_user, CourseInstructorRole(self.course.id)))
    def load_data(self):
        """Pull dates information from edx-when."""
        # (usage_key, 'due'): datetime.datetime(2019, 12, 11, 15, 0, tzinfo=<UTC>)
        # TODO: Merge https://github.com/edx/edx-when/pull/48 and add `outline_only=True`
        self.dates = get_dates_for_course(self.course_key, self.user)

        for (usage_key, field_name), date in self.dates.items():
            self.keys_to_schedule_fields[usage_key][field_name] = date

        course_usage_key = self.course_key.make_usage_key('course', 'course')
        self._course_start = self.keys_to_schedule_fields[course_usage_key].get('start')
        self._course_end = self.keys_to_schedule_fields[course_usage_key].get('end')
        self._is_beta_tester = user_has_role(self.user, CourseBetaTesterRole(self.course_key))
def get_user_role(user, course_id):
    """
    What type of access: staff or instructor does this user have in Studio?

    No code should use this for access control, only to quickly serialize the type of access
    where this code knows that Instructor trumps Staff and assumes the user has one or the other.

    This will not return student role because its purpose for using in Studio.

    :param course_id: the course_id of the course we're interested in
    """
    # afaik, this is only used in lti
    if auth.user_has_role(user, CourseInstructorRole(course_id)):
        return 'instructor'
    else:
        return 'staff'
Beispiel #25
0
        def change_state_and_verify_email(state, is_creator):
            """ Changes user state, verifies creator status, and verifies e-mail is sent based on transition """
            self._change_state(state)
            self.assertEqual(is_creator, auth.user_has_role(self.user, CourseCreatorRole()))

            context = {'studio_request_email': self.studio_request_email}
            if state == CourseCreator.GRANTED:
                template = 'emails/course_creator_granted.txt'
            elif state == CourseCreator.DENIED:
                template = 'emails/course_creator_denied.txt'
            else:
                template = 'emails/course_creator_revoked.txt'
            email_user.assert_called_with(
                mock_render_to_string('emails/course_creator_subject.txt', context),
                mock_render_to_string(template, context),
                self.studio_request_email
            )
Beispiel #26
0
    def test_change_status(self, email_user):
        """
        Tests that updates to state impact the creator group maintained in authz.py and that e-mails are sent.
        """
        def change_state_and_verify_email(state, is_creator):
            """ Changes user state, verifies creator status, and verifies e-mail is sent based on transition """
            self._change_state(state)
            self.assertEqual(
                is_creator, auth.user_has_role(self.user, CourseCreatorRole()))

            context = {'studio_request_email': self.studio_request_email}
            if state == CourseCreator.GRANTED:
                template = 'emails/course_creator_granted.txt'
            elif state == CourseCreator.DENIED:
                template = 'emails/course_creator_denied.txt'
            else:
                template = 'emails/course_creator_revoked.txt'
            email_user.assert_called_with(
                mock_render_to_string('emails/course_creator_subject.txt',
                                      context),
                mock_render_to_string(template, context),
                self.studio_request_email)

        with mock.patch.dict('django.conf.settings.FEATURES',
                             self.enable_creator_group_patch):

            # User is initially unrequested.
            self.assertFalse(auth.user_has_role(self.user,
                                                CourseCreatorRole()))

            change_state_and_verify_email(CourseCreator.GRANTED, True)

            change_state_and_verify_email(CourseCreator.DENIED, False)

            change_state_and_verify_email(CourseCreator.GRANTED, True)

            change_state_and_verify_email(CourseCreator.PENDING, False)

            change_state_and_verify_email(CourseCreator.GRANTED, True)

            change_state_and_verify_email(CourseCreator.UNREQUESTED, False)

            change_state_and_verify_email(CourseCreator.DENIED, False)
Beispiel #27
0
    def get(self, request):
        """Gets a list of all course enrollments for a user.

        Returns a list for the currently logged in user, or for the user named by the 'user' GET
        parameter. If the username does not match that of the currently logged in user, only
        courses for which the currently logged in user has the Staff or Admin role are listed.
        As a result, a course team member can find out which of their own courses a particular
        learner is enrolled in.

        Only the Staff or Admin role (granted on the Django administrative console as the staff
        or instructor permission) in individual courses gives the requesting user access to
        enrollment data. Permissions granted at the organizational level do not give a user
        access to enrollment data for all of that organization's courses.

        Users who have the global staff permission can access all enrollment data for all
        courses.
        """
        username = request.GET.get('user', request.user.username)
        try:
            enrollment_data = api.get_enrollments(username)
        except CourseEnrollmentError:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    "message":
                    ("An error occurred while retrieving enrollments for user '{username}'"
                     ).format(username=username)
                })
        if username == request.user.username or GlobalStaff().has_user(request.user) or \
                self.has_api_key_permissions(request):
            return Response(enrollment_data)
        filtered_data = []
        for enrollment in enrollment_data:
            course_key = CourseKey.from_string(
                enrollment["course_details"]["course_id"])
            if user_has_role(request.user, CourseStaffRole(course_key)):
                filtered_data.append(enrollment)
        return Response(filtered_data)
Beispiel #28
0
    def setUpTestData(cls):
        course_key = CourseKey.from_string("course-v1:OpenEdX+Outline+T1")
        # Users...
        cls.global_staff = User.objects.create_user('global_staff',
                                                    email='*****@*****.**',
                                                    is_staff=True)
        cls.student = User.objects.create_user('student',
                                               email='*****@*****.**',
                                               is_staff=False)
        cls.beta_tester = BetaTesterFactory(course_key=course_key)
        cls.anonymous_user = AnonymousUser()

        cls.course_key = course_key

        # The UsageKeys we're going to set up for date tests.
        cls.section_key = cls.course_key.make_usage_key('chapter', 'ch1')
        cls.seq_before_key = cls.course_key.make_usage_key(
            'sequential', 'seq_before')
        cls.seq_same_key = cls.course_key.make_usage_key(
            'sequential', 'seq_same')
        cls.seq_after_key = cls.course_key.make_usage_key(
            'sequential', 'seq_after')
        cls.seq_inherit_key = cls.course_key.make_usage_key(
            'sequential', 'seq_inherit')
        cls.seq_due_key = cls.course_key.make_usage_key(
            'sequential', 'seq_due')

        cls.all_seq_keys = [
            cls.seq_before_key,
            cls.seq_same_key,
            cls.seq_after_key,
            cls.seq_inherit_key,
            cls.seq_due_key,
        ]

        # Set scheduling information into edx-when for a single Section with
        # sequences starting at various times.
        set_dates_for_course(
            cls.course_key,
            [
                (cls.course_key.make_usage_key('course', 'course'), {
                    'start': datetime(2020, 5, 10, tzinfo=timezone.utc)
                }),
                (cls.section_key, {
                    'start': datetime(2020, 5, 15, tzinfo=timezone.utc)
                }),
                # Sequence that starts before containing Section.
                (cls.seq_before_key, {
                    'start': datetime(2020, 5, 14, tzinfo=timezone.utc)
                }),
                # Sequence starts at same time as containing Section.
                (cls.seq_same_key, {
                    'start': datetime(2020, 5, 15, tzinfo=timezone.utc)
                }),
                # Sequence starts after containing Section.
                (cls.seq_after_key, {
                    'start': datetime(2020, 5, 16, tzinfo=timezone.utc)
                }),
                # Sequence should inherit start information from Section.
                (cls.seq_inherit_key, {
                    'start': None
                }),
                # Sequence should inherit start information from Section, but has a due date set.
                (cls.seq_due_key, {
                    'start': None,
                    'due': datetime(2020, 5, 20, tzinfo=timezone.utc)
                }),
            ])
        visibility = VisibilityData(hide_from_toc=False,
                                    visible_to_staff_only=False)
        cls.outline = CourseOutlineData(
            course_key=cls.course_key,
            title="User Outline Test Course!",
            published_at=datetime(2020, 5, 20, tzinfo=timezone.utc),
            published_version="5ebece4b69dd593d82fe2020",
            days_early_for_beta=None,
            course_visibility=CourseVisibility.PRIVATE,
            sections=[
                CourseSectionData(
                    usage_key=cls.section_key,
                    title="Section",
                    visibility=visibility,
                    sequences=[
                        CourseLearningSequenceData(
                            usage_key=cls.seq_before_key,
                            title='Before',
                            visibility=visibility),
                        CourseLearningSequenceData(usage_key=cls.seq_same_key,
                                                   title='Same',
                                                   visibility=visibility),
                        CourseLearningSequenceData(usage_key=cls.seq_after_key,
                                                   title='After',
                                                   visibility=visibility),
                        CourseLearningSequenceData(
                            usage_key=cls.seq_inherit_key,
                            title='Inherit',
                            visibility=visibility),
                        CourseLearningSequenceData(
                            usage_key=cls.seq_due_key,
                            title='Due',
                            visibility=visibility,
                            inaccessible_after_due=True),
                    ])
            ],
            self_paced=False,
        )
        replace_course_outline(cls.outline)

        # Enroll student in the course
        cls.student.courseenrollment_set.create(course_id=cls.course_key,
                                                is_active=True,
                                                mode="audit")
        # Enroll beta tester in the course
        cls.beta_tester.courseenrollment_set.create(course_id=cls.course_key,
                                                    is_active=True,
                                                    mode="audit")
        assert user_has_role(cls.beta_tester,
                             CourseBetaTesterRole(cls.course_key))
        assert cls.outline.days_early_for_beta is None
Beispiel #29
0
 def test_creator_group_not_enabled(self):
     """
     Tests that CourseCreatorRole().has_user always returns True if ENABLE_CREATOR_GROUP
     and DISABLE_COURSE_CREATION are both not turned on.
     """
     assert user_has_role(self.user, CourseCreatorRole())