def test_is_certificate_invalid_with_invalid_cert(self): """ Verify that method return true if certificate is invalid. """ invalid_cert = CertificateInvalidationFactory.create( generated_certificate=self.certificate, invalidated_by=self.user ) # Invalidate user certificate self.certificate.invalidate() self.assertTrue( CertificateInvalidation.has_certificate_invalidation(self.user, self.course_id) ) # mark the entry as in-active. invalid_cert.active = False invalid_cert.save() # After making the certificate valid method will return false. self.assertFalse( CertificateInvalidation.has_certificate_invalidation(self.user, self.course_id) )
def is_certificate_invalid(student, course_key): """Check that whether the student in the course has been invalidated for receiving certificates. Arguments: student (user object): logged-in user course_key (CourseKey): The course identifier. Returns: Boolean denoting whether the student in the course is invalidated to receive certificates """ is_invalid = False certificate = GeneratedCertificate.certificate_for_student(student, course_key) if certificate is not None: is_invalid = CertificateInvalidation.has_certificate_invalidation(student, course_key) return is_invalid
def instructor_dashboard_2(request, course_id): """ Display the instructor dashboard for a course. """ try: course_key = CourseKey.from_string(course_id) except InvalidKeyError: log.error(u"Unable to find course with course key %s while loading the Instructor Dashboard.", course_id) return HttpResponseServerError() course = get_course_by_id(course_key, depth=0) access = { 'admin': request.user.is_staff, 'instructor': bool(has_access(request.user, 'instructor', course)), 'finance_admin': CourseFinanceAdminRole(course_key).has_user(request.user), 'sales_admin': CourseSalesAdminRole(course_key).has_user(request.user), 'staff': bool(has_access(request.user, 'staff', course)), 'forum_admin': has_forum_access(request.user, course_key, FORUM_ROLE_ADMINISTRATOR), } if not access['staff']: raise Http404() is_white_label = CourseMode.is_white_label(course_key) reports_enabled = configuration_helpers.get_value('SHOW_ECOMMERCE_REPORTS', False) sections = [ _section_course_info(course, access), _section_membership(course, access, is_white_label), _section_cohort_management(course, access), _section_discussions_management(course, access), _section_student_admin(course, access), _section_data_download(course, access), ] analytics_dashboard_message = None if show_analytics_dashboard_message(course_key): # Construct a URL to the external analytics dashboard analytics_dashboard_url = '{0}/courses/{1}'.format(settings.ANALYTICS_DASHBOARD_URL, unicode(course_key)) link_start = HTML("<a href=\"{}\" target=\"_blank\">").format(analytics_dashboard_url) analytics_dashboard_message = _( "To gain insights into student enrollment and participation {link_start}" "visit {analytics_dashboard_name}, our new course analytics product{link_end}." ) analytics_dashboard_message = Text(analytics_dashboard_message).format( link_start=link_start, link_end=HTML("</a>"), analytics_dashboard_name=settings.ANALYTICS_DASHBOARD_NAME) # Temporarily show the "Analytics" section until we have a better way of linking to Insights sections.append(_section_analytics(course, access)) # Check if there is corresponding entry in the CourseMode Table related to the Instructor Dashboard course course_mode_has_price = False paid_modes = CourseMode.paid_modes_for_course(course_key) if len(paid_modes) == 1: course_mode_has_price = True elif len(paid_modes) > 1: log.error( u"Course %s has %s course modes with payment options. Course must only have " u"one paid course mode to enable eCommerce options.", unicode(course_key), len(paid_modes) ) if settings.FEATURES.get('INDIVIDUAL_DUE_DATES') and access['instructor']: sections.insert(3, _section_extensions(course)) # Gate access to course email by feature flag & by course-specific authorization if BulkEmailFlag.feature_enabled(course_key): sections.append(_section_send_email(course, access)) # Gate access to Metrics tab by featue flag and staff authorization if settings.FEATURES['CLASS_DASHBOARD'] and access['staff']: sections.append(_section_metrics(course, access)) # Gate access to Ecommerce tab if course_mode_has_price and (access['finance_admin'] or access['sales_admin']): sections.append(_section_e_commerce(course, access, paid_modes[0], is_white_label, reports_enabled)) # Gate access to Special Exam tab depending if either timed exams or proctored exams # are enabled in the course user_has_access = any([ request.user.is_staff, CourseStaffRole(course_key).has_user(request.user), CourseInstructorRole(course_key).has_user(request.user) ]) course_has_special_exams = course.enable_proctored_exams or course.enable_timed_exams can_see_special_exams = course_has_special_exams and user_has_access and settings.FEATURES.get( 'ENABLE_SPECIAL_EXAMS', False) if can_see_special_exams: sections.append(_section_special_exams(course, access)) # Certificates panel # This is used to generate example certificates # and enable self-generated certificates for a course. # Note: This is hidden for all CCXs certs_enabled = CertificateGenerationConfiguration.current().enabled and not hasattr(course_key, 'ccx') if certs_enabled and access['admin']: sections.append(_section_certificates(course)) openassessment_blocks = modulestore().get_items( course_key, qualifiers={'category': 'openassessment'} ) # filter out orphaned openassessment blocks openassessment_blocks = [ block for block in openassessment_blocks if block.parent is not None ] if len(openassessment_blocks) > 0: sections.append(_section_open_response_assessment(request, course, openassessment_blocks, access)) disable_buttons = not _is_small_course(course_key) certificate_white_list = CertificateWhitelist.get_certificate_white_list(course_key) generate_certificate_exceptions_url = reverse( # pylint: disable=invalid-name 'generate_certificate_exceptions', kwargs={'course_id': unicode(course_key), 'generate_for': ''} ) generate_bulk_certificate_exceptions_url = reverse( # pylint: disable=invalid-name 'generate_bulk_certificate_exceptions', kwargs={'course_id': unicode(course_key)} ) certificate_exception_view_url = reverse( 'certificate_exception_view', kwargs={'course_id': unicode(course_key)} ) certificate_invalidation_view_url = reverse( # pylint: disable=invalid-name 'certificate_invalidation_view', kwargs={'course_id': unicode(course_key)} ) certificate_invalidations = CertificateInvalidation.get_certificate_invalidations(course_key) context = { 'course': course, 'studio_url': get_studio_url(course, 'course'), 'sections': sections, 'disable_buttons': disable_buttons, 'analytics_dashboard_message': analytics_dashboard_message, 'certificate_white_list': certificate_white_list, 'certificate_invalidations': certificate_invalidations, 'generate_certificate_exceptions_url': generate_certificate_exceptions_url, 'generate_bulk_certificate_exceptions_url': generate_bulk_certificate_exceptions_url, 'certificate_exception_view_url': certificate_exception_view_url, 'certificate_invalidation_view_url': certificate_invalidation_view_url, } return render_to_response('instructor/instructor_dashboard_2/instructor_dashboard_2.html', context)
def test_is_certificate_invalid_method(self): """ Verify that method return false if certificate is valid. """ self.assertFalse( CertificateInvalidation.has_certificate_invalidation(self.user, self.course_id) )
def instructor_dashboard_2(request, course_id): """ Display the instructor dashboard for a course. """ try: course_key = CourseKey.from_string(course_id) except InvalidKeyError: log.error( u"Unable to find course with course key %s while loading the Instructor Dashboard.", course_id) return HttpResponseServerError() course = get_course_by_id(course_key, depth=0) access = { 'admin': request.user.is_staff, 'instructor': bool(has_access(request.user, 'instructor', course)), 'finance_admin': CourseFinanceAdminRole(course_key).has_user(request.user), 'sales_admin': CourseSalesAdminRole(course_key).has_user(request.user), 'staff': bool(has_access(request.user, 'staff', course)), 'forum_admin': has_forum_access(request.user, course_key, FORUM_ROLE_ADMINISTRATOR), 'data_researcher': request.user.has_perm('student.can_research', course_key), } if not access['staff']: raise Http404() is_white_label = CourseMode.is_white_label(course_key) reports_enabled = configuration_helpers.get_value('SHOW_ECOMMERCE_REPORTS', False) sections = [ _section_course_info(course, access), _section_membership(course, access), _section_cohort_management(course, access), _section_discussions_management(course, access), _section_student_admin(course, access), _section_data_download(course, access), ] analytics_dashboard_message = None if show_analytics_dashboard_message(course_key): # Construct a URL to the external analytics dashboard analytics_dashboard_url = '{0}/courses/{1}'.format( settings.ANALYTICS_DASHBOARD_URL, six.text_type(course_key)) link_start = HTML(u"<a href=\"{}\" rel=\"noopener\" target=\"_blank\">" ).format(analytics_dashboard_url) analytics_dashboard_message = _( u"To gain insights into student enrollment and participation {link_start}" u"visit {analytics_dashboard_name}, our new course analytics product{link_end}." ) analytics_dashboard_message = Text(analytics_dashboard_message).format( link_start=link_start, link_end=HTML("</a>"), analytics_dashboard_name=settings.ANALYTICS_DASHBOARD_NAME) # Temporarily show the "Analytics" section until we have a better way of linking to Insights sections.append(_section_analytics(course, access)) # Check if there is corresponding entry in the CourseMode Table related to the Instructor Dashboard course course_mode_has_price = False paid_modes = CourseMode.paid_modes_for_course(course_key) if len(paid_modes) == 1: course_mode_has_price = True elif len(paid_modes) > 1: log.error( u"Course %s has %s course modes with payment options. Course must only have " u"one paid course mode to enable eCommerce options.", six.text_type(course_key), len(paid_modes)) if access['instructor'] and is_enabled_for_course(course_key): sections.insert(3, _section_extensions(course)) # Gate access to course email by feature flag & by course-specific authorization if is_bulk_email_feature_enabled(course_key): sections.append(_section_send_email(course, access)) # Gate access to Ecommerce tab if course_mode_has_price and (access['finance_admin'] or access['sales_admin']): sections.append( _section_e_commerce(course, access, paid_modes[0], is_white_label, reports_enabled)) # Gate access to Special Exam tab depending if either timed exams or proctored exams # are enabled in the course user_has_access = any([ request.user.is_staff, CourseStaffRole(course_key).has_user(request.user), CourseInstructorRole(course_key).has_user(request.user) ]) course_has_special_exams = course.enable_proctored_exams or course.enable_timed_exams can_see_special_exams = course_has_special_exams and user_has_access and settings.FEATURES.get( 'ENABLE_SPECIAL_EXAMS', False) if can_see_special_exams: sections.append(_section_special_exams(course, access)) # Certificates panel # This is used to generate example certificates # and enable self-generated certificates for a course. # Note: This is hidden for all CCXs certs_enabled = CertificateGenerationConfiguration.current( ).enabled and not hasattr(course_key, 'ccx') if certs_enabled and access['admin']: sections.append(_section_certificates(course)) openassessment_blocks = modulestore().get_items( course_key, qualifiers={'category': 'openassessment'}) # filter out orphaned openassessment blocks openassessment_blocks = [ block for block in openassessment_blocks if block.parent is not None ] if len(openassessment_blocks) > 0: sections.append( _section_open_response_assessment(request, course, openassessment_blocks, access)) disable_buttons = not _is_small_course(course_key) certificate_white_list = CertificateWhitelist.get_certificate_white_list( course_key) generate_certificate_exceptions_url = reverse( 'generate_certificate_exceptions', kwargs={ 'course_id': six.text_type(course_key), 'generate_for': '' }) generate_bulk_certificate_exceptions_url = reverse( 'generate_bulk_certificate_exceptions', kwargs={'course_id': six.text_type(course_key)}) certificate_exception_view_url = reverse( 'certificate_exception_view', kwargs={'course_id': six.text_type(course_key)}) certificate_invalidation_view_url = reverse( 'certificate_invalidation_view', kwargs={'course_id': six.text_type(course_key)}) certificate_invalidations = CertificateInvalidation.get_certificate_invalidations( course_key) context = { 'course': course, 'studio_url': get_studio_url(course, 'course'), 'sections': sections, 'disable_buttons': disable_buttons, 'analytics_dashboard_message': analytics_dashboard_message, 'certificate_white_list': certificate_white_list, 'certificate_invalidations': certificate_invalidations, 'generate_certificate_exceptions_url': generate_certificate_exceptions_url, 'generate_bulk_certificate_exceptions_url': generate_bulk_certificate_exceptions_url, 'certificate_exception_view_url': certificate_exception_view_url, 'certificate_invalidation_view_url': certificate_invalidation_view_url, 'xqa_server': settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"), } return render_to_response( 'instructor/instructor_dashboard_2/instructor_dashboard_2.html', context)
def test_is_certificate_invalid_method(self): """ Verify that method return false if certificate is valid. """ assert not CertificateInvalidation.has_certificate_invalidation( self.user, self.course_id)
def _can_generate_v2_certificate(user, course_key): """ Check if a v2 course certificate can be generated (created if it doesn't already exist, or updated if it does exist) for this user, in this course run. """ if not _is_using_v2_course_certificates(course_key): # This course run is not using the v2 course certificate feature log.info( f'{course_key} is not using v2 course certificates. Certificate cannot be generated.' ) return False if not auto_certificate_generation_enabled(): # Automatic certificate generation is globally disabled log.info( f'Automatic certificate generation is globally disabled. Certificate cannot be generated for ' f'{user.id} : {course_key}.') return False if CertificateInvalidation.has_certificate_invalidation(user, course_key): # The invalidation list prevents certificate generation log.info( f'{user.id} : {course_key} is on the certificate invalidation list. Certificate cannot be generated.' ) return False enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user( user, course_key) if enrollment_mode is None: log.info( f'{user.id} : {course_key} does not have an enrollment. Certificate cannot be generated.' ) return False if not modes_api.is_eligible_for_certificate(enrollment_mode): log.info( f'{user.id} : {course_key} has an enrollment mode of {enrollment_mode}, which is not eligible for an ' f'allowlist certificate. Certificate cannot be generated.') return False if not IDVerificationService.user_is_verified(user): log.info( f'{user.id} does not have a verified id. Certificate cannot be generated for {course_key}.' ) return False if _is_ccx_course(course_key): log.info( f'{course_key} is a CCX course. Certificate cannot be generated for {user.id}.' ) return False course = _get_course(course_key) if _is_beta_tester(user, course): log.info( f'{user.id} is a beta tester in {course_key}. Certificate cannot be generated.' ) return False if not _has_passing_grade(user, course): log.info( f'{user.id} does not have a passing grade in {course_key}. Certificate cannot be generated.' ) return False if not _can_generate_certificate_for_status(user, course_key): return False course = _get_course(course_key) if not has_html_certificates_enabled(course): log.info( f'{course_key} does not have HTML certificates enabled. Certificate cannot be generated for ' f'{user.id}.') return False log.info(f'V2 certificate can be generated for {user.id} : {course_key}') return True
def _can_generate_allowlist_certificate(user, course_key): """ Check if an allowlist certificate can be generated (created if it doesn't already exist, or updated if it does exist) for this user, in this course run. """ if not is_using_certificate_allowlist(course_key): # This course run is not using the allowlist feature log.info( f'{course_key} is not using the certificate allowlist. Allowlist certificate cannot be generated' f'for {user.id}.') return False if not _is_on_certificate_allowlist(user, course_key): log.info( f'{user.id} : {course_key} is not on the certificate allowlist. Allowlist certificate cannot be ' f'generated.') return False if not auto_certificate_generation_enabled(): # Automatic certificate generation is globally disabled log.info( f'Automatic certificate generation is globally disabled. Allowlist certificate cannot be generated' f'for {user.id} : {course_key}.') return False if CertificateInvalidation.has_certificate_invalidation(user, course_key): # The invalidation list overrides the allowlist log.info( f'{user.id} : {course_key} is on the certificate invalidation list. Allowlist certificate cannot be ' f'generated.') return False enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user( user, course_key) if enrollment_mode is None: log.info( f'{user.id} : {course_key} does not have an enrollment. Allowlist certificate cannot be generated.' ) return False if not modes_api.is_eligible_for_certificate(enrollment_mode): log.info( f'{user.id} : {course_key} has an enrollment mode of {enrollment_mode}, which is not eligible for an ' f'allowlist certificate. Certificate cannot be generated.') return False if not IDVerificationService.user_is_verified(user): log.info( f'{user.id} does not have a verified id. Allowlist certificate cannot be generated for {course_key}.' ) return False course = _get_course(course_key) if not has_html_certificates_enabled(course): log.info( f'{course_key} does not have HTML certificates enabled. Allowlist certificate cannot be generated for ' f'{user.id}.') return False log.info(f'{user.id} : {course_key} is on the certificate allowlist') return _can_generate_allowlist_certificate_for_status(user, course_key)