Esempio n. 1
0
    def test_user_status(self):
        # test for correct status when no error returned
        user = UserFactory.create()
        status = IDVerificationService.user_status(user)
        self.assertEquals(status, ('none', ''))

        # test for when one has been created
        attempt = SoftwareSecurePhotoVerification.objects.create(
            user=user, status='approved')
        status = IDVerificationService.user_status(user)
        self.assertEquals(status, ('approved', ''))

        # create another one for the same user, make sure the right one is
        # returned
        SoftwareSecurePhotoVerification.objects.create(
            user=user,
            status='denied',
            error_msg='[{"photoIdReasons": ["Not provided"]}]')
        status = IDVerificationService.user_status(user)
        self.assertEquals(status, ('approved', ''))

        # now delete the first one and verify that the denial is being handled
        # properly
        attempt.delete()
        status = IDVerificationService.user_status(user)
        self.assertEquals(status, ('must_reverify', ['id_image_missing']))
Esempio n. 2
0
    def test_user_status(self):
        # test for correct status when no error returned
        user = UserFactory.create()
        status = IDVerificationService.user_status(user)
        self.assertEquals(status, {'status': 'none', 'error': '', 'should_display': True})

        # test for when photo verification has been created
        SoftwareSecurePhotoVerification.objects.create(user=user, status='approved')
        status = IDVerificationService.user_status(user)
        self.assertEquals(status, {'status': 'approved', 'error': '', 'should_display': True})

        # create another photo verification for the same user, make sure the denial
        # is handled properly
        SoftwareSecurePhotoVerification.objects.create(
            user=user, status='denied', error_msg='[{"photoIdReasons": ["Not provided"]}]'
        )
        status = IDVerificationService.user_status(user)
        self.assertEquals(status, {'status': 'must_reverify', 'error': ['id_image_missing'], 'should_display': True})

        # test for when sso verification has been created
        SSOVerification.objects.create(user=user, status='approved')
        status = IDVerificationService.user_status(user)
        self.assertEquals(status, {'status': 'approved', 'error': '', 'should_display': False})

        # create another sso verification for the same user, make sure the denial
        # is handled properly
        SSOVerification.objects.create(user=user, status='denied')
        status = IDVerificationService.user_status(user)
        self.assertEquals(status, {'status': 'must_reverify', 'error': '', 'should_display': False})
Esempio n. 3
0
def _listen_for_id_verification_status_changed(sender, user, **kwargs):  # pylint: disable=unused-argument
    """
    Catches a track change signal, determines user status,
    calls fire_ungenerated_certificate_task for passing grades
    """
    if not auto_certificate_generation_enabled():
        return

    user_enrollments = CourseEnrollment.enrollments_for_user(user=user)

    grade_factory = CourseGradeFactory()
    expected_verification_status = IDVerificationService.user_status(user)
    expected_verification_status = expected_verification_status['status']
    for enrollment in user_enrollments:
        if grade_factory.read(user=user, course=enrollment.course_overview).passed:
            if fire_ungenerated_certificate_task(user, enrollment.course_id, expected_verification_status):
                message = (
                    u'Certificate generation task initiated for {user} : {course} via track change ' +
                    u'with verification status of {status}'
                )
                log.info(message.format(
                    user=user.id,
                    course=enrollment.course_id,
                    status=expected_verification_status
                ))
Esempio n. 4
0
def generate_certificate(self, **kwargs):
    """
    Generates a certificate for a single user.

    kwargs:
        - student: The student for whom to generate a certificate.
        - course_key: The course key for the course that the student is
            receiving a certificate in.
        - expected_verification_status: The expected verification status
            for the user.  When the status has changed, we double check
            that the actual verification status is as expected before
            generating a certificate, in the off chance that the database
            has not yet updated with the user's new verification status.
    """
    original_kwargs = kwargs.copy()
    student = User.objects.get(id=kwargs.pop('student'))
    course_key = CourseKey.from_string(kwargs.pop('course_key'))
    expected_verification_status = kwargs.pop('expected_verification_status',
                                              None)
    if expected_verification_status:
        actual_verification_status = IDVerificationService.user_status(student)
        if expected_verification_status != actual_verification_status:
            raise self.retry(kwargs=original_kwargs)
    generate_user_certificates(student=student,
                               course_key=course_key,
                               **kwargs)
Esempio n. 5
0
 def test_expired_verification(self):
     with freeze_time('2015-07-11') as frozen_datetime:
         # create approved photo verification for the user
         SoftwareSecurePhotoVerification.objects.create(
             user=self.user,
             status='approved',
             expiration_date=now() +
             timedelta(days=settings.VERIFY_STUDENT["DAYS_GOOD_FOR"]))
         frozen_datetime.move_to('2016-07-11')
         expected_status = {
             'status':
             'expired',
             'error':
             _("Your {platform_name} verification has expired.").format(
                 platform_name=configuration_helpers.get_value(
                     'platform_name', settings.PLATFORM_NAME)),
             'should_display':
             True,
             'verification_expiry':
             '',
             'status_date':
             ''
         }
         status = IDVerificationService.user_status(self.user)
         self.assertDictEqual(status, expected_status)
Esempio n. 6
0
def _listen_for_id_verification_status_changed(sender, user, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a signal indicating that the user's id verification status has changed.

    If needed, generate a certificate task.
    """
    if not auto_certificate_generation_enabled():
        return

    user_enrollments = CourseEnrollment.enrollments_for_user(user=user)

    grade_factory = CourseGradeFactory()
    expected_verification_status = IDVerificationService.user_status(user)
    expected_verification_status = expected_verification_status['status']
    for enrollment in user_enrollments:
        if can_generate_certificate_task(user, enrollment.course_id):
            log.info(
                f'{enrollment.course_id} is using V2 certificates. Attempt will be made to generate a V2 '
                f'certificate for {user.id}. Id verification status is {expected_verification_status}'
            )
            generate_certificate_task(user, enrollment.course_id)
        elif grade_factory.read(user=user,
                                course=enrollment.course_overview).passed:
            if _fire_ungenerated_certificate_task(
                    user, enrollment.course_id, expected_verification_status):
                message = (
                    'Certificate generation task initiated for {user} : {course} via track change '
                    + 'with verification status of {status}')
                log.info(
                    message.format(user=user.id,
                                   course=enrollment.course_id,
                                   status=expected_verification_status))
Esempio n. 7
0
    def _get_external_user_info(self, external_user_key, org_key):
        """
        Provided the external_user_key and org_key, return edx account info
        and program_enrollments_info if any. If we cannot identify the data,
        return empty object.
        """
        found_user = None
        result = {}
        try:
            users_by_key = get_users_by_external_keys_and_org_key(
                [external_user_key], org_key)
            found_user = users_by_key.get(external_user_key)
        except (BadOrganizationShortNameException,
                ProviderConfigurationException, ProviderDoesNotExistException):
            # We cannot identify edX user from external_user_key and org_key pair
            pass

        if found_user:
            try:
                user_social_auth = UserSocialAuth.objects.get(user=found_user)
            except UserSocialAuth.DoesNotExist:
                user_social_auth = None
            user_info = serialize_user_info(found_user, user_social_auth)
            result['user'] = user_info
            result['id_verification'] = IDVerificationService.user_status(
                found_user)
        enrollments = self._get_enrollments(
            external_user_key=external_user_key)
        if enrollments:
            result['enrollments'] = enrollments
        return result
Esempio n. 8
0
def generate_certificate(self, **kwargs):
    """
    Generates a certificate for a single user.

    kwargs:
        - student: The student for whom to generate a certificate.
        - course_key: The course key for the course that the student is
            receiving a certificate in.
        - expected_verification_status: The expected verification status
            for the user.  When the status has changed, we double check
            that the actual verification status is as expected before
            generating a certificate, in the off chance that the database
            has not yet updated with the user's new verification status.
    """
    original_kwargs = kwargs.copy()
    student = User.objects.get(id=kwargs.pop('student'))
    course_key = CourseKey.from_string(kwargs.pop('course_key'))
    expected_verification_status = kwargs.pop('expected_verification_status', None)
    if expected_verification_status:
        actual_verification_status = IDVerificationService.user_status(student)
        actual_verification_status = actual_verification_status['status']
        if expected_verification_status != actual_verification_status:
            logger.warn('Expected verification status {expected} '
                        'differs from actual verification status {actual} '
                        'for user {user} in course {course}'.format(
                            expected=expected_verification_status,
                            actual=actual_verification_status,
                            user=student.id,
                            course=course_key
                        ))
            raise self.retry(kwargs=original_kwargs)
    generate_user_certificates(student=student, course_key=course_key, **kwargs)
    def test_expired_verification(self, new_status):
        with freeze_time('2015-07-11') as frozen_datetime:
            # create approved photo verification for the user
            SoftwareSecurePhotoVerification.objects.create(user=self.user,
                                                           status='approved')
            frozen_datetime.move_to('2015-07-22')
            # create another according to status passed in.
            SoftwareSecurePhotoVerification.objects.create(user=self.user,
                                                           status=new_status)

            check_status = new_status
            status_date = ''
            if new_status in ('submitted', 'must_retry'):
                check_status = 'pending'
            elif new_status in ('created', 'ready'):
                check_status = 'none'
            elif new_status == 'denied':
                check_status = 'must_reverify'
            else:
                status_date = datetime.now(utc)

            expected_status = {
                'status': check_status,
                'error': '',
                'should_display': True,
                'verification_expiry': '',
                'status_date': status_date
            }
            status = IDVerificationService.user_status(self.user)
            self.assertDictEqual(status, expected_status)
    def _get_account_info(self, username_or_email, idp_provider=None):
        """
        Provided the edx account username or email, and the SAML provider selected,
        return edx account info and program_enrollments_info.
        If we cannot identify the user, return empty object and error.
        """
        try:
            user = User.objects.get(
                Q(username=username_or_email) | Q(email=username_or_email))
            user_social_auths = None
            user_social_auths = UserSocialAuth.objects.filter(user=user)
            if idp_provider:
                user_social_auths = user_social_auths.filter(
                    provider=idp_provider.backend_name)
            user_info = serialize_user_info(user, user_social_auths)
            enrollments = self._get_enrollments(user=user)
            result = {'user': user_info}
            if enrollments:
                result['enrollments'] = enrollments

            result['id_verification'] = IDVerificationService.user_status(user)
            return result, ''
        except User.DoesNotExist:
            return {}, 'Could not find edx account with {}'.format(
                username_or_email)
Esempio n. 11
0
def _listen_for_id_verification_status_changed(sender, user, **kwargs):  # pylint: disable=unused-argument
    """
    Catches a track change signal, determines user status,
    calls _fire_ungenerated_certificate_task for passing grades
    """
    if not auto_certificate_generation_enabled():
        return

    user_enrollments = CourseEnrollment.enrollments_for_user(user=user)

    grade_factory = CourseGradeFactory()
    expected_verification_status = IDVerificationService.user_status(user)
    expected_verification_status = expected_verification_status['status']
    for enrollment in user_enrollments:
        if is_using_certificate_allowlist_and_is_on_allowlist(
                user, enrollment.course_id):
            log.info(
                f'{enrollment.course_id} is using allowlist certificates, and the user {user.id} is on its '
                f'allowlist. Attempt will be made to generate an allowlist certificate. Id verification status '
                f'is {expected_verification_status}')
            generate_allowlist_certificate_task(user, enrollment.course_id)
        elif grade_factory.read(user=user,
                                course=enrollment.course_overview).passed:
            if _fire_ungenerated_certificate_task(
                    user, enrollment.course_id, expected_verification_status):
                message = (
                    u'Certificate generation task initiated for {user} : {course} via track change '
                    + u'with verification status of {status}')
                log.info(
                    message.format(user=user.id,
                                   course=enrollment.course_id,
                                   status=expected_verification_status))
Esempio n. 12
0
 def test_manual_verification(self):
     with freeze_time('2015-05-02'):
         # test for when manual verification has been created
         ManualVerification.objects.create(user=self.user, status='approved')
         status = IDVerificationService.user_status(self.user)
         expected_status = {'status': 'approved', 'error': '', 'should_display': False, 'verification_expiry': '',
                            'status_date': datetime.now(utc)}
         self.assertDictEqual(status, expected_status)
Esempio n. 13
0
 def test_approved_software_secure_verification(self):
     with freeze_time('2015-01-02'):
         # test for when photo verification has been created
         SoftwareSecurePhotoVerification.objects.create(user=self.user, status='approved')
         status = IDVerificationService.user_status(self.user)
         expected_status = {'status': 'approved', 'error': '', 'should_display': True, 'verification_expiry': '',
                            'status_date': datetime.now(utc)}
         self.assertDictEqual(status, expected_status)
Esempio n. 14
0
 def verification_status(self):
     """
     Returns a String of the verification status of learner.
     """
     if self.enrollment_object and self.enrollment_object.mode in CourseMode.VERIFIED_MODES:
         return IDVerificationService.user_status(self.effective_user)['status']
     # I know this looks weird (and is), but this is just so it is inline with what the
     # IDVerificationService.user_status method would return before a verification was created
     return 'none'
 def _construct_id_verification(self, user):
     """
     Helper function to create the SSO verified record for the user
     so that the user is ID Verified
     """
     SSOVerificationFactory(
         identity_provider_slug=self.org_key_list[0],
         user=user,
     )
     return IDVerificationService.user_status(user)
Esempio n. 16
0
 def test_denied_sso_verification(self):
     with freeze_time('2015-04-02'):
         # create denied sso verification for the user, make sure the denial
         # is handled properly
         SSOVerification.objects.create(user=self.user, status='denied')
         status = IDVerificationService.user_status(self.user)
         expected_status = {
             'status': 'must_reverify', 'error': '', 'should_display': False,
             'verification_expiry': '', 'status_date': ''
         }
         self.assertDictEqual(status, expected_status)
Esempio n. 17
0
    def test_search_username_user_no_enrollment(self, mocked_render):
        created_user, expected_user_info = self._construct_user(
            'user_connected', self.org_key_list[0], self.external_user_key)
        self.client.get(self.url, data={'edx_user': created_user.email})
        expected_info = {
            'user': expected_user_info,
            'id_verification': IDVerificationService.user_status(created_user),
        }

        render_call_dict = mocked_render.call_args[0][1]
        assert expected_info == render_call_dict['learner_program_enrollments']
Esempio n. 18
0
 def test_no_verification(self):
     with freeze_time('2014-12-12'):
         status = IDVerificationService.user_status(self.user)
         expected_status = {
             'status': 'none',
             'error': '',
             'should_display': True,
             'verification_expiry': '',
             'status_date': ''
         }
         self.assertDictEqual(status, expected_status)
Esempio n. 19
0
    def test_user_status(self):
        # test for correct status when no error returned
        user = UserFactory.create()
        status = IDVerificationService.user_status(user)
        self.assertDictEqual(status, {'status': 'none', 'error': '', 'should_display': True})

        # test for when photo verification has been created
        SoftwareSecurePhotoVerification.objects.create(user=user, status='approved')
        status = IDVerificationService.user_status(user)
        self.assertDictEqual(status, {'status': 'approved', 'error': '', 'should_display': True})

        # create another photo verification for the same user, make sure the denial
        # is handled properly
        SoftwareSecurePhotoVerification.objects.create(
            user=user, status='denied', error_msg='[{"photoIdReasons": ["Not provided"]}]'
        )
        status = IDVerificationService.user_status(user)
        self.assertDictEqual(status, {'status': 'must_reverify', 'error': ['id_image_missing'], 'should_display': True})

        # test for when sso verification has been created
        SSOVerification.objects.create(user=user, status='approved')
        status = IDVerificationService.user_status(user)
        self.assertDictEqual(status, {'status': 'approved', 'error': '', 'should_display': False})

        # create another sso verification for the same user, make sure the denial
        # is handled properly
        SSOVerification.objects.create(user=user, status='denied')
        status = IDVerificationService.user_status(user)
        self.assertDictEqual(status, {'status': 'must_reverify', 'error': '', 'should_display': False})

        # test for when manual verification has been created
        ManualVerification.objects.create(user=user, status='approved')
        status = IDVerificationService.user_status(user)
        self.assertDictEqual(status, {'status': 'approved', 'error': '', 'should_display': False})
Esempio n. 20
0
 def verify_identity_url(self):
     """
     Returns a String to the location to verify a learner's identity
     Note: This might return an absolute URL (if the verification MFE is enabled) or a relative
         URL. The serializer will make the relative URL absolute so any consumers can treat this
         as a full URL.
     """
     if self.enrollment_object and self.enrollment_object.mode in CourseMode.VERIFIED_MODES:
         verification_status = IDVerificationService.user_status(self.effective_user)['status']
         if verification_status == 'must_reverify':
             return IDVerificationService.get_verify_location()
         else:
             return IDVerificationService.get_verify_location(self.course_key)
Esempio n. 21
0
 def test_denied_software_secure_verification(self):
     with freeze_time('2015-2-02'):
         # create denied photo verification for the user, make sure the denial
         # is handled properly
         SoftwareSecurePhotoVerification.objects.create(
             user=self.user, status='denied', error_msg='[{"photoIdReasons": ["Not provided"]}]'
         )
         status = IDVerificationService.user_status(self.user)
         expected_status = {
             'status': 'must_reverify', 'error': ['id_image_missing'],
             'should_display': True, 'verification_expiry': '', 'status_date': '',
         }
         self.assertDictEqual(status, expected_status)
Esempio n. 22
0
 def get(self, request):
     """
     Handle the GET request.
     """
     verification_status = IDVerificationService.user_status(request.user)
     expiration_datetime = IDVerificationService.get_expiration_datetime(request.user, ['approved'])
     can_verify = can_verify_now(verification_status, expiration_datetime)
     data = {
         'status': verification_status['status'],
         'can_verify': can_verify,
     }
     if expiration_datetime:
         data['expires'] = expiration_datetime
     return Response(data)
Esempio n. 23
0
 def test_expiring_software_secure_verification(self, new_status):
     with freeze_time('2015-07-11') as frozen_datetime:
         # create approved photo verification for the user
         SoftwareSecurePhotoVerification.objects.create(user=self.user, status='approved')
         expiring_datetime = datetime.now(utc)
         frozen_datetime.move_to('2015-07-14')
         # create another according to status passed in.
         SoftwareSecurePhotoVerification.objects.create(user=self.user, status=new_status)
         status_date = expiring_datetime
         if new_status == 'approved':
             status_date = datetime.now(utc)
         expected_status = {'status': 'approved', 'error': '', 'should_display': True, 'verification_expiry': '',
                            'status_date': status_date}
         status = IDVerificationService.user_status(self.user)
         self.assertDictEqual(status, expected_status)
Esempio n. 24
0
def generate_certificate(self, **kwargs):
    """
    Generates a certificate for a single user.

    kwargs:
        - student: The student for whom to generate a certificate.
        - course_key: The course key for the course that the student is
            receiving a certificate in.
        - expected_verification_status: The expected verification status
            for the user.  When the status has changed, we double check
            that the actual verification status is as expected before
            generating a certificate, in the off chance that the database
            has not yet updated with the user's new verification status.
        - v2_certificate: A flag indicating whether to generate a v2 course certificate
        - generation_mode: Only used when emitting an event for V2 certificates. Options are "self" (implying the user
            generated the cert themself) and "batch" for everything else.
    """
    original_kwargs = kwargs.copy()
    student = User.objects.get(id=kwargs.pop('student'))
    course_key = CourseKey.from_string(kwargs.pop('course_key'))
    expected_verification_status = kwargs.pop('expected_verification_status',
                                              None)
    v2_certificate = kwargs.pop('v2_certificate', False)
    status = kwargs.pop('status', CertificateStatuses.downloadable)
    generation_mode = kwargs.pop('generation_mode', 'batch')

    if v2_certificate:
        generate_course_certificate(user=student,
                                    course_key=course_key,
                                    status=status,
                                    generation_mode=generation_mode)
        return

    if expected_verification_status:
        actual_verification_status = IDVerificationService.user_status(student)
        actual_verification_status = actual_verification_status['status']
        if expected_verification_status != actual_verification_status:
            log.warning('Expected verification status {expected} '
                        'differs from actual verification status {actual} '
                        'for user {user} in course {course}'.format(
                            expected=expected_verification_status,
                            actual=actual_verification_status,
                            user=student.id,
                            course=course_key))
            raise self.retry(kwargs=original_kwargs)
    generate_user_certificates(student=student,
                               course_key=course_key,
                               **kwargs)
Esempio n. 25
0
def generate_certificate(self, **kwargs):
    """
    Generates a certificate for a single user.

    kwargs:
        - student: The student for whom to generate a certificate.
        - course_key: The course key for the course that the student is
            receiving a certificate in.
        - expected_verification_status: The expected verification status
            for the user.  When the status has changed, we double check
            that the actual verification status is as expected before
            generating a certificate, in the off chance that the database
            has not yet updated with the user's new verification status.
        - allowlist_certificate: A flag indicating whether to generate an allowlist certificate (which is V2 of
            whitelisted certificates)
        - v2_certificate: A flag indicating whether to generate a v2 course certificate
    """
    original_kwargs = kwargs.copy()
    student = User.objects.get(id=kwargs.pop('student'))
    course_key = CourseKey.from_string(kwargs.pop('course_key'))
    expected_verification_status = kwargs.pop('expected_verification_status', None)
    allowlist_certificate = kwargs.pop('allowlist_certificate', False)
    v2_certificate = kwargs.pop('v2_certificate', False)

    if allowlist_certificate:
        generate_allowlist_certificate(user=student, course_key=course_key)
        return

    if v2_certificate:
        # TODO: will be implemented in MICROBA-923
        log.warning(f'Ignoring v2 certificate task request for {student.id}: {course_key}')
        return

    if expected_verification_status:
        actual_verification_status = IDVerificationService.user_status(student)
        actual_verification_status = actual_verification_status['status']
        if expected_verification_status != actual_verification_status:
            log.warning(
                'Expected verification status {expected} '
                'differs from actual verification status {actual} '
                'for user {user} in course {course}'.format(
                    expected=expected_verification_status,
                    actual=actual_verification_status,
                    user=student.id,
                    course=course_key
                ))
            raise self.retry(kwargs=original_kwargs)
    generate_user_certificates(student=student, course_key=course_key, **kwargs)
Esempio n. 26
0
 def test_override_verification(self, verification_type):
     with freeze_time('2015-07-11') as frozen_datetime:
         # create approved photo verification for the user
         SoftwareSecurePhotoVerification.objects.create(user=self.user,
                                                        status='approved')
         frozen_datetime.move_to('2015-07-14')
         verification_type.objects.create(user=self.user, status='approved')
         expected_status = {
             'status': 'approved',
             'error': '',
             'should_display': False,
             'verification_expiry': '',
             'status_date': datetime.now(utc)
         }
         status = IDVerificationService.user_status(self.user)
         self.assertDictEqual(status, expected_status)
def _listen_for_id_verification_status_changed(sender, user, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a signal indicating that the user's id verification status has changed.
    """
    if not auto_certificate_generation_enabled():
        return

    user_enrollments = CourseEnrollment.enrollments_for_user(user=user)
    expected_verification_status = IDVerificationService.user_status(user)
    expected_verification_status = expected_verification_status['status']

    for enrollment in user_enrollments:
        log.info(
            f'Attempt will be made to generate a course certificate for {user.id} : {enrollment.course_id}. Id '
            f'verification status is {expected_verification_status}')
        generate_certificate_task(user, enrollment.course_id)
Esempio n. 28
0
    def get(self, request, **kwargs):  # lint-amnesty, pylint: disable=missing-function-docstring
        username = kwargs.get('username')
        User = get_user_model()
        try:
            user = User.objects.get(username=username)
            user_status = IDVerificationService.user_status(user)
            if user_status.get('status') == 'none':
                raise Http404

            return Response({
                "is_verified": user_status.get('status') == 'approved',
                "status": user_status.get('status'),
                "expiration_datetime": user_status.get('verification_expiry', '')
            })

        except User.DoesNotExist:
            raise Http404  # lint-amnesty, pylint: disable=raise-missing-from
    def _get_external_user_info(self,
                                external_user_key,
                                org_key,
                                idp_provider=None):
        """
        Provided the external_user_key and org_key, return edx account info
        and program_enrollments_info if any. If we cannot identify the data,
        return empty object.
        """
        found_user = None
        result = {}
        try:
            users_by_key = get_users_by_external_keys_and_org_key(
                [external_user_key], org_key)
            # Remove entries with no corresponding user and convert keys to lowercase
            users_by_key_lower = {
                key.lower(): value
                for key, value in users_by_key.items() if value
            }
            found_user = users_by_key_lower.get(external_user_key.lower())
        except (BadOrganizationShortNameException,
                ProviderDoesNotExistException):
            # We cannot identify edX user from external_user_key and org_key pair
            pass

        enrollments = self._get_enrollments(
            external_user_key=external_user_key)
        if enrollments:
            result['enrollments'] = enrollments
        if found_user:
            user_social_auths = UserSocialAuth.objects.filter(user=found_user)
            if idp_provider:
                user_social_auths = user_social_auths.filter(
                    provider=idp_provider.backend_name)
            user_info = serialize_user_info(found_user, user_social_auths)
            result['user'] = user_info
            result['id_verification'] = IDVerificationService.user_status(
                found_user)
        elif 'enrollments' in result:
            result['user'] = {'external_user_key': external_user_key}

        return result
Esempio n. 30
0
    def get(self, request, **kwargs):
        username = kwargs.get('username')
        User = get_user_model()
        try:
            user = User.objects.get(username=username)
            user_status = IDVerificationService.user_status(user)
            if user_status.get('status') == 'none':
                raise Http404

            return Response({
                "is_verified":
                user_status.get('status') == 'approved',
                "status":
                user_status.get('status'),
                "expiration_datetime":
                user_status.get('verification_expiry', '')
            })

        except User.DoesNotExist:
            raise Http404
Esempio n. 31
0
 def test_override_verification(self, verification_type):
     with freeze_time('2015-07-11') as frozen_datetime:
         # create approved photo verification for the user
         SoftwareSecurePhotoVerification.objects.create(
             user=self.user,
             status='approved',
             expiration_date=now() + timedelta(days=settings.VERIFY_STUDENT["DAYS_GOOD_FOR"])
         )
         frozen_datetime.move_to('2015-07-14')
         verification_type.objects.create(
             user=self.user,
             status='approved',
             expiration_date=now() + timedelta(days=settings.VERIFY_STUDENT["DAYS_GOOD_FOR"])
         )
         expected_status = {
             'status': 'approved', 'error': '', 'should_display': False,
             'verification_expiry': '', 'status_date': now()
         }
         status = IDVerificationService.user_status(self.user)
         self.assertDictEqual(status, expected_status)
Esempio n. 32
0
    def get(self, request):
        """
        Render the reverification flow.

        Most of the work is done client-side by composing the same
        Backbone views used in the initial verification flow.
        """
        status, __ = IDVerificationService.user_status(request.user)

        expiration_datetime = IDVerificationService.get_expiration_datetime(
            request.user)
        can_reverify = False
        if expiration_datetime:
            if is_verification_expiring_soon(expiration_datetime):
                # The user has an active verification, but the verification
                # is set to expire within "EXPIRING_SOON_WINDOW" days (default is 4 weeks).
                # In this case user can resubmit photos for reverification.
                can_reverify = True

        # If the user has no initial verification or if the verification
        # process is still ongoing 'pending' or expired then allow the user to
        # submit the photo verification.
        # A photo verification is marked as 'pending' if its status is either
        # 'submitted' or 'must_retry'.

        if status in ["none", "must_reverify", "expired", "pending"
                      ] or can_reverify:
            context = {
                "user_full_name":
                request.user.profile.name,
                "platform_name":
                configuration_helpers.get_value('PLATFORM_NAME',
                                                settings.PLATFORM_NAME),
                "capture_sound":
                staticfiles_storage.url("audio/camera_capture.wav"),
            }
            return render_to_response("verify_student/reverify.html", context)
        else:
            context = {"status": status}
            return render_to_response(
                "verify_student/reverify_not_allowed.html", context)
Esempio n. 33
0
    def get(self, request):
        """
        Render the reverification flow.

        Most of the work is done client-side by composing the same
        Backbone views used in the initial verification flow.
        """
        verification_status = IDVerificationService.user_status(request.user)
        expiration_datetime = IDVerificationService.get_expiration_datetime(request.user, ['approved'])
        if can_verify_now(verification_status, expiration_datetime):
            context = {
                "user_full_name": request.user.profile.name,
                "platform_name": configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
                "capture_sound": staticfiles_storage.url("audio/camera_capture.wav"),
            }
            return render_to_response("verify_student/reverify.html", context)
        else:
            context = {
                "status": verification_status['status']
            }
            return render_to_response("verify_student/reverify_not_allowed.html", context)
Esempio n. 34
0
    def get(self, request):
        """
        Render the reverification flow.

        Most of the work is done client-side by composing the same
        Backbone views used in the initial verification flow.
        """
        verification_status = IDVerificationService.user_status(request.user)

        expiration_datetime = IDVerificationService.get_expiration_datetime(request.user, ['approved'])
        can_reverify = False
        if expiration_datetime:
            if is_verification_expiring_soon(expiration_datetime):
                # The user has an active verification, but the verification
                # is set to expire within "EXPIRING_SOON_WINDOW" days (default is 4 weeks).
                # In this case user can resubmit photos for reverification.
                can_reverify = True

        # If the user has no initial verification or if the verification
        # process is still ongoing 'pending' or expired then allow the user to
        # submit the photo verification.
        # A photo verification is marked as 'pending' if its status is either
        # 'submitted' or 'must_retry'.

        if verification_status['status'] in ["none", "must_reverify", "expired", "pending"] or can_reverify:
            context = {
                "user_full_name": request.user.profile.name,
                "platform_name": configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
                "capture_sound": staticfiles_storage.url("audio/camera_capture.wav"),
            }
            return render_to_response("verify_student/reverify.html", context)
        else:
            context = {
                "status": verification_status['status']
            }
            return render_to_response("verify_student/reverify_not_allowed.html", context)
Esempio n. 35
0
 def verification_status(self):
     """Return the verification status for this user."""
     verification_status = IDVerificationService.user_status(self.user)
     return verification_status['status']
Esempio n. 36
0
def student_dashboard(request):
    """
    Provides the LMS dashboard view

    TODO: This is lms specific and does not belong in common code.

    Arguments:
        request: The request object.

    Returns:
        The dashboard response.

    """
    user = request.user
    if not UserProfile.objects.filter(user=user).exists():
        return redirect(reverse('account_settings'))

    platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME)

    enable_verified_certificates = configuration_helpers.get_value(
        'ENABLE_VERIFIED_CERTIFICATES',
        settings.FEATURES.get('ENABLE_VERIFIED_CERTIFICATES')
    )
    display_course_modes_on_dashboard = configuration_helpers.get_value(
        'DISPLAY_COURSE_MODES_ON_DASHBOARD',
        settings.FEATURES.get('DISPLAY_COURSE_MODES_ON_DASHBOARD', True)
    )
    activation_email_support_link = configuration_helpers.get_value(
        'ACTIVATION_EMAIL_SUPPORT_LINK', settings.ACTIVATION_EMAIL_SUPPORT_LINK
    ) or settings.SUPPORT_SITE_LINK

    # Get the org whitelist or the org blacklist for the current site
    site_org_whitelist, site_org_blacklist = get_org_black_and_whitelist_for_site()
    course_enrollments = list(get_course_enrollments(user, site_org_whitelist, site_org_blacklist))

    # Get the entitlements for the user and a mapping to all available sessions for that entitlement
    # If an entitlement has no available sessions, pass through a mock course overview object
    (course_entitlements,
     course_entitlement_available_sessions,
     unfulfilled_entitlement_pseudo_sessions) = get_filtered_course_entitlements(
        user,
        site_org_whitelist,
        site_org_blacklist
    )

    # Record how many courses there are so that we can get a better
    # understanding of usage patterns on prod.
    monitoring_utils.accumulate('num_courses', len(course_enrollments))

    # Sort the enrollment pairs by the enrollment date
    course_enrollments.sort(key=lambda x: x.created, reverse=True)

    # Retrieve the course modes for each course
    enrolled_course_ids = [enrollment.course_id for enrollment in course_enrollments]
    __, unexpired_course_modes = CourseMode.all_and_unexpired_modes_for_courses(enrolled_course_ids)
    course_modes_by_course = {
        course_id: {
            mode.slug: mode
            for mode in modes
        }
        for course_id, modes in iteritems(unexpired_course_modes)
    }

    # Check to see if the student has recently enrolled in a course.
    # If so, display a notification message confirming the enrollment.
    enrollment_message = _create_recent_enrollment_message(
        course_enrollments, course_modes_by_course
    )
    course_optouts = Optout.objects.filter(user=user).values_list('course_id', flat=True)

    sidebar_account_activation_message = ''
    banner_account_activation_message = ''
    display_account_activation_message_on_sidebar = configuration_helpers.get_value(
        'DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR',
        settings.FEATURES.get('DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR', False)
    )

    # Display activation message in sidebar if DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR
    # flag is active. Otherwise display existing message at the top.
    if display_account_activation_message_on_sidebar and not user.is_active:
        sidebar_account_activation_message = render_to_string(
            'registration/account_activation_sidebar_notice.html',
            {
                'email': user.email,
                'platform_name': platform_name,
                'activation_email_support_link': activation_email_support_link
            }
        )
    elif not user.is_active:
        banner_account_activation_message = render_to_string(
            'registration/activate_account_notice.html',
            {'email': user.email}
        )

    enterprise_message = get_dashboard_consent_notification(request, user, course_enrollments)

    # Disable lookup of Enterprise consent_required_course due to ENT-727
    # Will re-enable after fixing WL-1315
    consent_required_courses = set()
    enterprise_customer_name = None

    # Account activation message
    account_activation_messages = [
        message for message in messages.get_messages(request) if 'account-activation' in message.tags
    ]

    # Global staff can see what courses encountered an error on their dashboard
    staff_access = False
    errored_courses = {}
    if has_access(user, 'staff', 'global'):
        # Show any courses that encountered an error on load
        staff_access = True
        errored_courses = modulestore().get_errored_courses()

    show_courseware_links_for = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if has_access(request.user, 'load', enrollment.course_overview)
    )

    # Find programs associated with course runs being displayed. This information
    # is passed in the template context to allow rendering of program-related
    # information on the dashboard.
    meter = ProgramProgressMeter(request.site, user, enrollments=course_enrollments)
    ecommerce_service = EcommerceService()
    inverted_programs = meter.invert_programs()

    urls, programs_data = {}, {}
    bundles_on_dashboard_flag = WaffleFlag(WaffleFlagNamespace(name=u'student.experiments'), u'bundles_on_dashboard')

    # TODO: Delete this code and the relevant HTML code after testing LEARNER-3072 is complete
    if bundles_on_dashboard_flag.is_enabled() and inverted_programs and inverted_programs.items():
        if len(course_enrollments) < 4:
            for program in inverted_programs.values():
                try:
                    program_uuid = program[0]['uuid']
                    program_data = get_programs(request.site, uuid=program_uuid)
                    program_data = ProgramDataExtender(program_data, request.user).extend()
                    skus = program_data.get('skus')
                    checkout_page_url = ecommerce_service.get_checkout_page_url(*skus)
                    program_data['completeProgramURL'] = checkout_page_url + '&bundle=' + program_data.get('uuid')
                    programs_data[program_uuid] = program_data
                except:  # pylint: disable=bare-except
                    pass

    # Construct a dictionary of course mode information
    # used to render the course list.  We re-use the course modes dict
    # we loaded earlier to avoid hitting the database.
    course_mode_info = {
        enrollment.course_id: complete_course_mode_info(
            enrollment.course_id, enrollment,
            modes=course_modes_by_course[enrollment.course_id]
        )
        for enrollment in course_enrollments
    }

    # Determine the per-course verification status
    # This is a dictionary in which the keys are course locators
    # and the values are one of:
    #
    # VERIFY_STATUS_NEED_TO_VERIFY
    # VERIFY_STATUS_SUBMITTED
    # VERIFY_STATUS_APPROVED
    # VERIFY_STATUS_MISSED_DEADLINE
    #
    # Each of which correspond to a particular message to display
    # next to the course on the dashboard.
    #
    # If a course is not included in this dictionary,
    # there is no verification messaging to display.
    verify_status_by_course = check_verify_status_by_course(user, course_enrollments)
    cert_statuses = {
        enrollment.course_id: cert_info(request.user, enrollment.course_overview)
        for enrollment in course_enrollments
    }

    # only show email settings for Mongo course and when bulk email is turned on
    show_email_settings_for = frozenset(
        enrollment.course_id for enrollment in course_enrollments if (
            BulkEmailFlag.feature_enabled(enrollment.course_id)
        )
    )

    # Verification Attempts
    # Used to generate the "you must reverify for course x" banner
    verification_status = IDVerificationService.user_status(user)
    verification_errors = get_verification_error_reasons_for_display(verification_status['error'])

    # Gets data for midcourse reverifications, if any are necessary or have failed
    statuses = ["approved", "denied", "pending", "must_reverify"]
    reverifications = reverification_info(statuses)

    block_courses = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if is_course_blocked(
            request,
            CourseRegistrationCode.objects.filter(
                course_id=enrollment.course_id,
                registrationcoderedemption__redeemed_by=request.user
            ),
            enrollment.course_id
        )
    )

    enrolled_courses_either_paid = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if enrollment.is_paid_course()
    )

    # If there are *any* denied reverifications that have not been toggled off,
    # we'll display the banner
    denied_banner = any(item.display for item in reverifications["denied"])

    # Populate the Order History for the side-bar.
    order_history_list = order_history(
        user,
        course_org_filter=site_org_whitelist,
        org_filter_out_set=site_org_blacklist
    )

    # get list of courses having pre-requisites yet to be completed
    courses_having_prerequisites = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if enrollment.course_overview.pre_requisite_courses
    )
    courses_requirements_not_met = get_pre_requisite_courses_not_completed(user, courses_having_prerequisites)

    if 'notlive' in request.GET:
        redirect_message = _("The course you are looking for does not start until {date}.").format(
            date=request.GET['notlive']
        )
    elif 'course_closed' in request.GET:
        redirect_message = _("The course you are looking for is closed for enrollment as of {date}.").format(
            date=request.GET['course_closed']
        )
    else:
        redirect_message = ''

    valid_verification_statuses = ['approved', 'must_reverify', 'pending', 'expired']
    display_sidebar_on_dashboard = (len(order_history_list) or
                                    (verification_status['status'] in valid_verification_statuses and
                                    verification_status['should_display']))

    # Filter out any course enrollment course cards that are associated with fulfilled entitlements
    for entitlement in [e for e in course_entitlements if e.enrollment_course_run is not None]:
        course_enrollments = [
            enr for enr in course_enrollments if entitlement.enrollment_course_run.course_id != enr.course_id
        ]

    context = {
        'urls': urls,
        'programs_data': programs_data,
        'enterprise_message': enterprise_message,
        'consent_required_courses': consent_required_courses,
        'enterprise_customer_name': enterprise_customer_name,
        'enrollment_message': enrollment_message,
        'redirect_message': redirect_message,
        'account_activation_messages': account_activation_messages,
        'course_enrollments': course_enrollments,
        'course_entitlements': course_entitlements,
        'course_entitlement_available_sessions': course_entitlement_available_sessions,
        'unfulfilled_entitlement_pseudo_sessions': unfulfilled_entitlement_pseudo_sessions,
        'course_optouts': course_optouts,
        'banner_account_activation_message': banner_account_activation_message,
        'sidebar_account_activation_message': sidebar_account_activation_message,
        'staff_access': staff_access,
        'errored_courses': errored_courses,
        'show_courseware_links_for': show_courseware_links_for,
        'all_course_modes': course_mode_info,
        'cert_statuses': cert_statuses,
        'credit_statuses': _credit_statuses(user, course_enrollments),
        'show_email_settings_for': show_email_settings_for,
        'reverifications': reverifications,
        'verification_display': verification_status['should_display'],
        'verification_status': verification_status['status'],
        'verification_status_by_course': verify_status_by_course,
        'verification_errors': verification_errors,
        'block_courses': block_courses,
        'denied_banner': denied_banner,
        'billing_email': settings.PAYMENT_SUPPORT_EMAIL,
        'user': user,
        'logout_url': reverse('logout'),
        'platform_name': platform_name,
        'enrolled_courses_either_paid': enrolled_courses_either_paid,
        'provider_states': [],
        'order_history_list': order_history_list,
        'courses_requirements_not_met': courses_requirements_not_met,
        'nav_hidden': True,
        'inverted_programs': inverted_programs,
        'show_program_listing': ProgramsApiConfig.is_enabled(),
        'show_dashboard_tabs': True,
        'disable_courseware_js': True,
        'display_course_modes_on_dashboard': enable_verified_certificates and display_course_modes_on_dashboard,
        'display_sidebar_on_dashboard': display_sidebar_on_dashboard,
    }

    if ecommerce_service.is_enabled(request.user):
        context.update({
            'use_ecommerce_payment_flow': True,
            'ecommerce_payment_page': ecommerce_service.payment_page_url(),
        })

    # Gather urls for course card resume buttons.
    resume_button_urls = _get_urls_for_resume_buttons(user, course_enrollments)
    # There must be enough urls for dashboard.html. Template creates course
    # cards for "enrollments + entitlements".
    resume_button_urls += ['' for entitlement in course_entitlements]
    context.update({
        'resume_button_urls': resume_button_urls
    })

    response = render_to_response('dashboard.html', context)
    set_user_info_cookie(response, request)
    return response