def _get_recipient_queryset(user_id, to_option, course_id, course_location): """ Returns a query set of email recipients corresponding to the requested to_option category. `to_option` is either SEND_TO_MYSELF, SEND_TO_STAFF, or SEND_TO_ALL. Recipients who are in more than one category (e.g. enrolled in the course and are staff or self) will be properly deduped. """ if to_option not in TO_OPTIONS: log.error("Unexpected bulk email TO_OPTION found: %s", to_option) raise Exception( "Unexpected bulk email TO_OPTION found: {0}".format(to_option)) if to_option == SEND_TO_MYSELF: recipient_qset = User.objects.filter(id=user_id) else: staff_qset = CourseStaffRole(course_location).users_with_role() instructor_qset = CourseInstructorRole( course_location).users_with_role() recipient_qset = staff_qset | instructor_qset if to_option == SEND_TO_ALL: # We also require students to have activated their accounts to # provide verification that the provided email address is valid. enrollment_qset = User.objects.filter( is_active=True, courseenrollment__course_id=course_id, courseenrollment__is_active=True) recipient_qset = recipient_qset | enrollment_qset recipient_qset = recipient_qset.distinct() recipient_qset = recipient_qset.order_by('pk') return recipient_qset
def test_staff_csv(self): """Download and validate staff CSV""" self._setstaff_login() self._add_edx4edx() def_ms = modulestore() course = def_ms.get_course('MITx/edx4edx/edx4edx') CourseStaffRole(course.location).add_users(self.user) response = self.client.post(reverse('sysadmin_staffing'), { 'action': 'get_staff_csv', }) self.assertIn('attachment', response['Content-Disposition']) self.assertEqual('text/csv', response['Content-Type']) columns = [ _('course_id'), _('role'), _('username'), _('email'), _('full_name'), ] self.assertIn(','.join('"' + c + '"' for c in columns), response.content) self._rm_edx4edx()
def test_gitlog_courseteam_access(self): """ Ensure course team users are allowed to access only their own course. """ self._mkdir(getattr(settings, 'GIT_REPO_DIR')) self._setstaff_login() self._add_edx4edx() self.user.is_staff = False self.user.save() logged_in = self.client.login(username=self.user.username, password='******') response = self.client.get(reverse('gitlogs')) # Make sure our non privileged user doesn't have access to all logs self.assertEqual(response.status_code, 404) # Or specific logs response = self.client.get( reverse('gitlogs_detail', kwargs={'course_id': 'MITx/edx4edx/edx4edx'})) self.assertEqual(response.status_code, 404) # Add user as staff in course team def_ms = modulestore() course = def_ms.get_course('MITx/edx4edx/edx4edx') CourseStaffRole(course.location).add_users(self.user) self.assertTrue(CourseStaffRole(course.location).has_user(self.user)) logged_in = self.client.login(username=self.user.username, password='******') self.assertTrue(logged_in) response = self.client.get( reverse('gitlogs_detail', kwargs={'course_id': 'MITx/edx4edx/edx4edx'})) self.assertIn('======> IMPORTING course to location', response.content) self._rm_edx4edx()
def _has_access_to_location(user, location, access_level, course_context): ''' Returns True if the given user has access_level (= staff or instructor) access to a location. For now this is equivalent to having staff / instructor access to the course location.course. This means that user is in the staff_* group or instructor_* group, or is an overall admin. TODO (vshnayder): this needs to be changed to allow per-course_id permissions, not per-course (e.g. staff in 2012 is different from 2013, but maybe some people always have access) course is a string: the course field of the location being accessed. location = location access_level = string, either "staff" or "instructor" ''' if user is None or (not user.is_authenticated()): debug("Deny: no user or anon user") return False if is_masquerading_as_student(user): return False if GlobalStaff().has_user(user): debug("Allow: user.is_staff") return True if access_level not in ('staff', 'instructor'): log.debug("Error in access._has_access_to_location access_level=%s unknown", access_level) debug("Deny: unknown access level") return False staff_access = ( CourseStaffRole(location, course_context).has_user(user) or OrgStaffRole(location).has_user(user) ) if staff_access and access_level == 'staff': debug("Allow: user has course staff access") return True instructor_access = ( CourseInstructorRole(location, course_context).has_user(user) or OrgInstructorRole(location).has_user(user) ) if instructor_access and access_level in ('staff', 'instructor'): debug("Allow: user has course instructor access") return True debug("Deny: user did not have correct access") return False
def get(self, request): """Displays course Enrollment and staffing course statistics""" if not request.user.is_staff: raise Http404 data = [] courses = self.get_courses() for (cdir, course) in courses.items(): # pylint: disable=unused-variable datum = [course.display_name, course.id] datum += [ CourseEnrollment.objects.filter(course_id=course.id).count() ] datum += [ CourseStaffRole(course.location).users_with_role().count() ] datum += [ ','.join([ x.username for x in CourseInstructorRole( course.location).users_with_role() ]) ] data.append(datum) datatable = dict(header=[ _('Course Name'), _('course_id'), _('# enrolled'), _('# staff'), _('instructors') ], title=_('Enrollment information for all courses'), data=data) context = { 'datatable': datatable, 'msg': self.msg, 'djangopid': os.getpid(), 'modeflag': { 'staffing': 'active-section' }, 'mitx_version': getattr(settings, 'VERSION_STRING', ''), } return render_to_response(self.template_name, context)
def setUp(self): clear_existing_modulestores() courses = modulestore().get_courses() self.course_id = "edX/toy/2012_Fall" self.toy = modulestore().get_course(self.course_id) # Create two accounts self.student = '*****@*****.**' self.instructor = '*****@*****.**' self.password = '******' self.create_account('u1', self.student, self.password) self.create_account('u2', self.instructor, self.password) self.activate_user(self.student) self.activate_user(self.instructor) CourseStaffRole(self.toy.location).add_users( User.objects.get(email=self.instructor)) self.logout() self.login(self.instructor, self.password) self.enroll(self.toy)
def make_instructor(course, user_email): """ Makes a given user an instructor in a course. """ CourseStaffRole(course.location).add_users(User.objects.get(email=user_email))
def course(self, create, extracted, **kwargs): if extracted is None: raise ValueError( "Must specify a course location for a course staff user") CourseStaffRole(extracted).add_users(self)
def make_instructor(course): """ Create an instructor for the course.""" CourseStaffRole(course.location).add_users(User.objects.get(email=self.instructor))
def make_instructor(course): CourseStaffRole(course.location).add_users( User.objects.get(email=self.instructor))
def test_revoke_twice(self): user = self.staff[0] revoke_access(self.course, user, 'staff') self.assertFalse(CourseStaffRole(self.course.location).has_user(user))
def test_allow_twice(self): user = UserFactory() allow_access(self.course, user, 'staff') allow_access(self.course, user, 'staff') self.assertTrue(CourseStaffRole(self.course.location).has_user(user))
def get(self, request, *args, **kwargs): """Shows logs of imports that happened as a result of a git import""" course_id = kwargs.get('course_id') # Set mongodb defaults even if it isn't defined in settings mongo_db = { 'host': 'localhost', 'user': '', 'password': '', 'db': 'xlog', } # Allow overrides if hasattr(settings, 'MONGODB_LOG'): for config_item in [ 'host', 'user', 'password', 'db', ]: mongo_db[config_item] = settings.MONGODB_LOG.get( config_item, mongo_db[config_item]) mongouri = 'mongodb://{user}:{password}@{host}/{db}'.format(**mongo_db) error_msg = '' try: if mongo_db['user'] and mongo_db['password']: mdb = mongoengine.connect(mongo_db['db'], host=mongouri) else: mdb = mongoengine.connect(mongo_db['db'], host=mongo_db['host']) except mongoengine.connection.ConnectionError: logging.exception('Unable to connect to mongodb to save log, ' 'please check MONGODB_LOG settings.') if course_id is None: # Require staff if not going to specific course if not request.user.is_staff: raise Http404 cilset = CourseImportLog.objects.all().order_by('-created') else: try: course = get_course_by_id(course_id) except Exception: # pylint: disable=broad-except cilset = None error_msg = _('Cannot find course {0}').format(course_id) # Allow only course team, instructors, and staff if not (request.user.is_staff or CourseInstructorRole( course.location).has_user(request.user) or CourseStaffRole( course.location).has_user(request.user)): raise Http404 log.debug('course_id={0}'.format(course_id)) cilset = CourseImportLog.objects.filter( course_id=course_id).order_by('-created') log.debug('cilset length={0}'.format(len(cilset))) mdb.disconnect() context = { 'cilset': cilset, 'course_id': course_id, 'error_msg': error_msg } return render_to_response(self.template_name, context)