def post(self, request, user_id): # pylint: disable=unused-argument """ Deletes all user data for the particular user_id from all configured backends """ if not request.user.has_perm('accounts.can_retire_user'): return Response(status=403) results = {} code = 200 seen = set() # pylint: disable=no-member attempts = ProctoredExamStudentAttempt.objects.filter(user_id=user_id).select_related('proctored_exam') if attempts: for attempt in attempts: backend_name = attempt.proctored_exam.backend if backend_name in seen or not attempt.taking_as_proctored: continue backend_user_id = obscured_user_id(user_id, backend_name) LOG.info(u'retiring user %s from %s', user_id, backend_name) try: result = get_backend_provider(name=backend_name).retire_user(backend_user_id) except ProctoredBaseException: LOG.exception(u'attempting to delete %s (%s) from %s', user_id, backend_user_id, backend_name) result = False if result is not None: results[backend_name] = result if not result: code = 500 seen.add(backend_name) return Response(data=results, status=code)
def post(self, request, user_id): # pylint: disable=unused-argument """ Deletes all user data for the particular user_id from all configured backends """ if not request.user.has_perm('accounts.can_retire_user'): return Response(status=403) from django.apps import apps choices = apps.get_app_config('edx_proctoring').get_backend_choices() results = {} code = 200 if ProctoredExamStudentAttempt.objects.filter(user_id=user_id): for backend_name, verbose_name in choices: backend_user_id = obscured_user_id(user_id, backend_name) LOG.info('retiring user %s from %s', user_id, backend_name) try: result = get_backend_provider(name=backend_name).retire_user(backend_user_id) except ProctoredBaseException: LOG.exception('attempting to delete %s (%s) from %s', user_id, backend_user_id, verbose_name) result = False if result is not None: results[backend_name] = result if not result: code = 500 return Response(data=results, status=code)
def post(self, request, user_id): # pylint: disable=unused-argument """ Deletes all user data for the particular user_id from all configured backends """ if not request.user.has_perm('accounts.can_retire_user'): return Response(status=403) results = {} code = 200 seen = set() attempts = ProctoredExamStudentAttempt.objects.filter(user_id=user_id).select_related('proctored_exam') if attempts: for attempt in attempts: backend_name = attempt.proctored_exam.backend if backend_name in seen or not attempt.taking_as_proctored: continue backend_user_id = obscured_user_id(user_id, backend_name) LOG.info('retiring user %s from %s', user_id, backend_name) try: result = get_backend_provider(name=backend_name).retire_user(backend_user_id) except ProctoredBaseException: LOG.exception('attempting to delete %s (%s) from %s', user_id, backend_user_id, backend_name) result = False if result is not None: results[backend_name] = result if not result: code = 500 seen.add(backend_name) return Response(data=results, status=code)
def get(self, request, course_id, exam_id=None): """ Redirect to dashboard for a given course and optional exam_id """ exam = None attempt_id = None ext_exam_id = None show_configuration_dashboard = False if exam_id: exam = get_exam_by_id(exam_id) # the exam_id in the url is our database id (for ease of lookups) # but the backend needs its external id for the instructor dashboard ext_exam_id = exam['external_id'] attempt_id = request.GET.get('attempt', None) # only show the configuration dashboard if an exam_id is passed in show_configuration_dashboard = request.GET.get('config', '').lower() == 'true' else: found_backend = None for exam in get_all_exams_for_course(course_id, True): exam_backend = exam['backend'] or settings.PROCTORING_BACKENDS.get('DEFAULT', None) if found_backend and exam_backend != found_backend: # In this case, what are we supposed to do?! # It should not be possible to get in this state, because # course teams will be prevented from updating the backend after the course start date error_message = "Multiple backends for course %r %r != %r" % (course_id, found_backend, exam['backend']) return Response(data=error_message, status=400) else: found_backend = exam_backend if exam is None: error = _('No exams in course {course_id}.').format(course_id=course_id) else: backend = get_backend_provider(exam) if backend: user = { 'id': obscured_user_id(request.user.id, exam['backend']), 'full_name': request.user.get_full_name(), 'email': request.user.email } url = backend.get_instructor_url( exam['course_id'], user, exam_id=ext_exam_id, attempt_id=attempt_id, show_configuration_dashboard=show_configuration_dashboard ) if url: return redirect(url) else: error = _('No instructor dashboard for {proctor_service}').format( proctor_service=backend.verbose_name) else: error = _('No proctored exams in course {course_id}').format(course_id=course_id) return Response(data=error, status=404, headers={'X-Frame-Options': 'sameorigin'})
def get(self, request, course_id, exam_id=None): """ Redirect to dashboard for a given course and optional exam_id """ exam = None backend = None ext_exam_id = None attempt_id = None show_configuration_dashboard = False if exam_id: exam = get_exam_by_id(exam_id) backend = get_backend_provider(exam=exam) # the exam_id in the url is our database id (for ease of lookups) # but the backend needs its external id for the instructor dashboard ext_exam_id = exam['external_id'] attempt_id = request.GET.get('attempt', None) # only show the configuration dashboard if an exam_id is passed in show_configuration_dashboard = request.GET.get('config', '').lower() == 'true' else: existing_backend_name = None for exam in get_all_exams_for_course(course_id, True): if not exam.get('is_proctored'): # We should only get backends of exams which are configured to be proctored continue exam_backend_name = exam.get('backend') backend = get_backend_provider(name=exam_backend_name) if existing_backend_name and exam_backend_name != existing_backend_name: # In this case, what are we supposed to do?! # It should not be possible to get in this state, because # course teams will be prevented from updating the backend after the course start date error_message = u"Multiple backends for course %r %r != %r" % ( course_id, existing_backend_name, exam_backend_name ) return Response(data=error_message, status=400) else: existing_backend_name = exam_backend_name if not exam: return Response( data=_(u'No exams in course {course_id}.').format(course_id=course_id), status=404, headers={'X-Frame-Options': 'sameorigin'} ) if not backend: return Response( data=_(u'No proctored exams in course {course_id}').format(course_id=course_id), status=404, headers={'X-Frame-Options': 'sameorigin'} ) user = { 'id': obscured_user_id(request.user.id, exam['backend']), 'full_name': request.user.profile.name, 'email': request.user.email } url = backend.get_instructor_url( exam['course_id'], user, exam_id=ext_exam_id, attempt_id=attempt_id, show_configuration_dashboard=show_configuration_dashboard ) if not url: return Response( data=_(u'No instructor dashboard for {proctor_service}').format( proctor_service=backend.verbose_name ), status=404, headers={'X-Frame-Options': 'sameorigin'} ) return redirect(url)
def test_obscured_user_id(self): user_id = 32432455 expected_obscured_user_id = '9b82efd5d28f1a170b23b8f648c3093e75a0a0ca' self.assertEqual(expected_obscured_user_id, obscured_user_id(user_id))