Beispiel #1
0
    def test_create_account(self):
        # Create a new account, which should have empty account settings by default.
        create_account(self.USERNAME, self.PASSWORD, self.EMAIL)

        # Retrieve the account settings
        user = User.objects.get(username=self.USERNAME)
        request = RequestFactory().get("/api/user/v1/accounts/")
        request.user = user
        account_settings = get_account_settings(request)

        # Expect a date joined field but remove it to simplify the following comparison
        self.assertIsNotNone(account_settings['date_joined'])
        del account_settings['date_joined']

        # Expect all the values to be defaulted
        self.assertEqual(account_settings, {
            'username': self.USERNAME,
            'email': self.EMAIL,
            'name': u'',
            'gender': None,
            'goals': None,
            'is_active': False,
            'level_of_education': None,
            'mailing_address': None,
            'year_of_birth': None,
            'country': None,
            'bio': None,
            'profile_image': {
                'has_image': False,
                'image_url_full': request.build_absolute_uri('/static/default_50.png'),
                'image_url_small': request.build_absolute_uri('/static/default_10.png'),
            },
            'requires_parental_consent': True,
            'language_proficiencies': [],
        })
Beispiel #2
0
    def test_create_account(self):
        # Create a new account, which should have empty account settings by default.
        create_account(self.USERNAME, self.PASSWORD, self.EMAIL)

        # Retrieve the account settings
        user = User.objects.get(username=self.USERNAME)
        request = RequestFactory().get("/api/user/v1/accounts/")
        request.user = user
        account_settings = get_account_settings(request)

        # Expect a date joined field but remove it to simplify the following comparison
        self.assertIsNotNone(account_settings['date_joined'])
        del account_settings['date_joined']

        # Expect all the values to be defaulted
        self.assertEqual(account_settings, {
            'username': self.USERNAME,
            'email': self.EMAIL,
            'name': u'',
            'gender': None,
            'goals': None,
            'is_active': False,
            'level_of_education': None,
            'mailing_address': None,
            'year_of_birth': None,
            'country': None,
            'bio': None,
            'profile_image': {
                'has_image': False,
                'image_url_full': request.build_absolute_uri('/static/default_50.png'),
                'image_url_small': request.build_absolute_uri('/static/default_10.png'),
            },
            'requires_parental_consent': True,
            'language_proficiencies': [],
        })
    def test_browserid(self):
        # you're on the root page
        request = RequestFactory().get('/')
        context = context_processors.browserid(request)
        result = context['redirect_next']()
        eq_(result, request.build_absolute_uri())

        # you're on some other page with a query string
        request = RequestFactory().get('/some/other/page', {'foo': 'bar'})
        context = context_processors.browserid(request)
        result = context['redirect_next']()
        eq_(result, request.build_absolute_uri())
        ok_('?foo=bar' in result)

        # you're on the /login/ page
        request = RequestFactory().get(reverse('crashstats:login'))
        context = context_processors.browserid(request)
        result = context['redirect_next']()
        home_url = reverse('crashstats:home',
                           args=(settings.DEFAULT_PRODUCT, ))
        eq_(result, home_url)

        # you're on a page with a `?next=` query string
        # you're on some other page with a query string
        request = RequestFactory().get('/', {'next': '/some/page'})
        context = context_processors.browserid(request)
        result = context['redirect_next']()
        eq_(result, '/some/page')
    def test_browserid(self):
        # you're on the root page
        request = RequestFactory().get('/')
        context = context_processors.browserid(request)
        result = context['redirect_next']()
        eq_(result, request.build_absolute_uri())

        # you're on some other page with a query string
        request = RequestFactory().get('/some/other/page', {'foo': 'bar'})
        context = context_processors.browserid(request)
        result = context['redirect_next']()
        eq_(result, request.build_absolute_uri())
        ok_('?foo=bar' in result)

        # you're on the /login/ page
        request = RequestFactory().get(reverse('crashstats:login'))
        context = context_processors.browserid(request)
        result = context['redirect_next']()
        home_url = reverse('home:home', args=(settings.DEFAULT_PRODUCT,))
        eq_(result, home_url)

        # you're on a page with a `?next=` query string
        # you're on some other page with a query string
        request = RequestFactory().get('/', {'next': '/some/page'})
        context = context_processors.browserid(request)
        result = context['redirect_next']()
        eq_(result, '/some/page')
Beispiel #5
0
    def test_create_account(self):
        # Create a new account, which should have empty account settings by default.
        self.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
        # Retrieve the account settings
        user = User.objects.get(username=self.USERNAME)
        request = RequestFactory().get("/api/user/v1/accounts/")
        request.user = user
        account_settings = get_account_settings(request)[0]

        # Expect a date joined and last login field but remove it to simplify the following comparison
        assert account_settings['date_joined'] is not None
        assert account_settings['last_login'] is not None
        del account_settings['date_joined']
        del account_settings['last_login']

        # Expect all the values to be defaulted
        assert account_settings == {
            'username': self.USERNAME,
            'email': self.EMAIL,
            'id': user.id,
            'name': self.USERNAME,
            'activation_key': user.registration.activation_key,
            'gender': None,
            'goals': '',
            'is_active': False,
            'level_of_education': None,
            'mailing_address': '',
            'year_of_birth': None,
            'country': None,
            'state': None,
            'social_links': [],
            'bio': None,
            'profile_image': {
                'has_image':
                False,
                'image_url_full':
                request.build_absolute_uri('/static/default_50.png'),
                'image_url_small':
                request.build_absolute_uri('/static/default_10.png')
            },
            'requires_parental_consent': True,
            'language_proficiencies': [],
            'account_privacy': PRIVATE_VISIBILITY,
            'accomplishments_shared': False,
            'extended_profile': [],
            'secondary_email': None,
            'secondary_email_enabled': None,
            'time_zone': None,
            'course_certificates': None,
            'phone_number': None,
            'pending_name_change': None,
            'is_verified_name_enabled': False,
        }
Beispiel #6
0
def test_invalid_page_param():
    url = '%s?%s' % (reverse('search'), 'page=a')
    request = RequestFactory().get(url)
    queryset = range(100)
    paginated = paginate(request, queryset)
    eq_(paginated.url,
        request.build_absolute_uri(request.path) + '?')
Beispiel #7
0
def test_paginated_url():
    """Avoid duplicating page param in pagination."""
    url = '%s?%s' % (reverse('search'), 'q=bookmarks&page=2')
    request = RequestFactory().get(url)
    queryset = [{}, {}]
    paginated = paginate(request, queryset)
    eq_(paginated.url,
        request.build_absolute_uri(request.path) + '?q=bookmarks')
Beispiel #8
0
def test_paginated_url():
    """Avoid duplicating page param in pagination."""
    url = "%s?%s" % (reverse("search"), "q=bookmarks&page=2")
    request = RequestFactory().get(url)
    queryset = [{}, {}]
    paginated = paginate(request, queryset)
    eq_(paginated.url,
        request.build_absolute_uri(request.path) + "?q=bookmarks")
Beispiel #9
0
def test_paginated_url():
    """Avoid duplicating page param in pagination."""
    url = '%s?%s' % (reverse('search'), 'q=bookmarks&page=2')
    request = RequestFactory().get(url)
    queryset = [{}, {}]
    paginated = paginate(request, queryset)
    eq_(paginated.url,
        request.build_absolute_uri(request.path) + '?q=bookmarks')
class DocumentSerializerTestCase(ClearContentTypesTransactionTestCase):
    fixtures = ['projects.json']

    def setUp(self):
        self.dummy_request = RequestFactory().get('/')
        self.context = {'request': self.dummy_request}

        self.project = Project.objects.get(slug='emma')
        self.user = self.project.members.get()

        self.document = main_models.Document.objects.create(
            creator=self.user,
            last_updater=self.user,
            project=self.project,
            description='<div>Title</div>'
        )

    def test_document_serializer(self):
        serializer = en_serializers.DocumentSerializer(
            instance=self.document, context=self.context,
            include_embeds=True)

        transcript_url = self.dummy_request.build_absolute_uri(
            '/projects/emma/documents/{}/transcript/'.format(self.document.id))

        self.assertEqual(serializer.data['transcript'], transcript_url)
        self.assertEqual(serializer.data['embedded'][transcript_url], None)

        transcript = main_models.Transcript.objects.create(
            creator=self.user,
            last_updater=self.user,
            document=self.document,
            markup='What the text says.'
        )

        self.assertEqual(
            self.dummy_request.build_absolute_uri(
                transcript.get_absolute_url()),
            transcript_url)

        serializer = en_serializers.DocumentSerializer(
            instance=self.document, context=self.context,
            include_embeds=True)
        self.assertNotEqual(serializer.data['embedded'][transcript_url], None)
 def test_verification_parameters(self, verify_mock):
     """
     Verify that the signature validaton library method is called using the
     correct parameters derived from the HttpRequest.
     """
     body = 'oauth_signature_method=HMAC-SHA1&oauth_version=1.0'
     content_type = 'application/x-www-form-urlencoded'
     request = RequestFactory().post('/url', body, content_type=content_type)
     headers = {'Content-Type': content_type}
     SignatureValidator(self.lti_consumer).verify(request)
     verify_mock.assert_called_once_with(
         request.build_absolute_uri(), 'POST', body, headers)
 def test_verification_parameters(self, verify_mock):
     """
     Verify that the signature validaton library method is called using the
     correct parameters derived from the HttpRequest.
     """
     body = 'oauth_signature_method=HMAC-SHA1&oauth_version=1.0'
     content_type = 'application/x-www-form-urlencoded'
     request = RequestFactory().post('/url', body, content_type=content_type)
     headers = {'Content-Type': content_type}
     SignatureValidator().verify(request)
     verify_mock.assert_called_once_with(
         request.build_absolute_uri(), 'POST', body, headers)
Beispiel #13
0
    def test_create_account(self):
        # Create a new account, which should have empty account settings by default.
        create_account(self.USERNAME, self.PASSWORD, self.EMAIL)

        # Retrieve the account settings
        user = User.objects.get(username=self.USERNAME)
        request = RequestFactory().get("/api/user/v1/accounts/")
        request.user = user
        account_settings = get_account_settings(request)

        # Expect a date joined field but remove it to simplify the following comparison
        self.assertIsNotNone(account_settings["date_joined"])
        del account_settings["date_joined"]

        # Expect all the values to be defaulted
        self.assertEqual(
            account_settings,
            {
                "username": self.USERNAME,
                "email": self.EMAIL,
                "name": u"",
                "gender": None,
                "goals": None,
                "is_active": False,
                "level_of_education": None,
                "mailing_address": None,
                "year_of_birth": None,
                "country": None,
                "bio": None,
                "profile_image": {
                    "has_image": False,
                    "image_url_full": request.build_absolute_uri("/static/default_50.png"),
                    "image_url_small": request.build_absolute_uri("/static/default_10.png"),
                },
                "requires_parental_consent": True,
                "language_proficiencies": [],
                "account_privacy": None,
            },
        )
class TopicSerializerTestCase(ClearContentTypesTransactionTestCase):
    fixtures = ['projects.json']

    def setUp(self):
        self.dummy_request = RequestFactory().get('/')
        self.context = {'request': self.dummy_request}

        self.project = Project.objects.get(slug='emma')
        self.user = self.project.members.get()

        self.topic = main_models.Topic.objects.create(
            creator=self.user,
            last_updater=self.user,
            project=self.project,
            preferred_name='Emma Goldman'
        )

    def test_topic_serializer(self):
        serializer = en_serializers.TopicSerializer(
            instance=self.topic,
            context=self.context,
            include_embeds=True
        )

        base_url = self.dummy_request.build_absolute_uri(
            self.topic.get_absolute_url())
        wn_topic_url = base_url + 'w/'
        project_topic_url = base_url + 'p/'

        self.assertEqual(serializer.data['url'], base_url)

        self.assertDictEqual(serializer.data['wn_data'], {
            "@graph": {
                "@id": wn_topic_url,
                "@graph": {
                    "url": base_url,
                    "preferred_name": "Emma Goldman",
                    "alternate_names": [],
                    "related_topics": [],
                    "markup": None,
                    "markup_html": None
                }
            }
        })

        self.assertDictEqual(serializer.data['linked_data'], {
            "@graph": {
                "@id": project_topic_url,
                "@graph": {}
            }
        })
Beispiel #15
0
    def test_invite_url_sent_triggered_correctly(self, mock_signal):
        invite_url = reverse('invitations:accept-invite',
                             args=[self.invite.key])
        request = RequestFactory().get('/')
        invite_url = request.build_absolute_uri(invite_url)

        self.invite.send_invitation(request)

        self.assertTrue(mock_signal.called)
        self.assertEqual(mock_signal.call_count, 1)

        mock_signal.assert_called_with(
            instance=self.invite,
            invite_url_sent=invite_url,
            inviter=self.user,
            sender=Invitation,
        )
Beispiel #16
0
    def test_invite_url_sent_triggered_correctly(self, mock_signal):
        invite_url = reverse('invitations:accept-invite',
                             args=[self.invite.key])
        request = RequestFactory().get('/')
        invite_url = request.build_absolute_uri(invite_url)

        self.invite.send_invitation(request)

        self.assertTrue(mock_signal.called)
        self.assertEqual(mock_signal.call_count, 1)

        mock_signal.assert_called_with(
            instance=self.invite,
            invite_url_sent=invite_url,
            inviter=self.user,
            sender=Invitation,
        )
Beispiel #17
0
class HydraLinksTestCase(ClearContentTypesTransactionTestCase):
    fixtures = ['projects.json']

    def setUp(self):
        self.user = User.objects.get(email='*****@*****.**')
        self.project = Project.objects.get(slug='emma')
        self.dummy_req = RequestFactory().get('/')
        self.client.login(username='******', password='******')

    def test_topic_ld(self):
        topic = Topic.objects.create(
            preferred_name='Hippolyte Havel',
            project=self.project,
            creator=self.user,
            last_updater=self.user)

        absolute_url = self.dummy_req.build_absolute_uri(topic.get_absolute_url())


        response = self.client.put(
            reverse('api:topics-proj-detail', args=[self.project.slug, topic.id]),
            json.dumps({ 'should': 'disappear' }),
            content_type='application/json'
        )
        self.assertEqual(response.status_code, 200)

        topic.refresh_from_db()
        self.assertEqual(topic.ld, {})


        response = self.client.put(
            reverse('api:topics-proj-detail', args=[self.project.slug, topic.id]),
            json.dumps({
                'should': 'disappear',
                '@id': absolute_url,
                'http://example.com/name': 'Hippolyte Havel'
            }),
            content_type='application/json'
        )
        self.assertEqual(response.status_code, 200)
        topic.refresh_from_db()
        self.assertEqual(topic.ld, {
            '@id': absolute_url,
            'http://example.com/name': 'Hippolyte Havel'
        })
Beispiel #18
0
    def test_invite_url_sent_triggered_correctly(
            self, mock_signal, sent_invitation_by_user_a, user_a):
        invite_url = reverse('invitations:accept-invite',
                             args=[sent_invitation_by_user_a.key])
        request = RequestFactory().get('/')
        invite_url = request.build_absolute_uri(invite_url)

        sent_invitation_by_user_a.send_invitation(request)

        assert mock_signal.called
        assert mock_signal.call_count == 1

        mock_signal.assert_called_with(
            instance=sent_invitation_by_user_a,
            invite_url_sent=invite_url,
            inviter=user_a,
            sender=Invitation,
        )
Beispiel #19
0
    def setUp(self):

        # Параметри, при яких декоратор пропускає до функції:
        user = DummyUser().create_dummy_user(username='******')
        user.has_perms = Mock()
        user.has_perms.return_value = True

        user2 = DummyUser().create_dummy_user(username='******')
        user2.has_perms = Mock()
        user2.has_perms.return_value = True

        root = DummyFolder().create_dummy_root_folder()
        object = DummyFolder().create_dummy_report(root,
                                                   id=1,
                                                   filename='report1',
                                                   user=user)

        object2 = DummyFolder().create_dummy_report(root,
                                                    id=2,
                                                    filename='report2')

        model = Report

        request = RequestFactory()
        request.build_absolute_uri = Mock()
        request.build_absolute_uri.return_value = ""  # path
        request.get_full_path = Mock()
        request.get_full_path.return_value = ""  # path
        request.user = user

        view_func = Mock()
        view_func.return_value = 'passed'

        test_func = Mock()
        test_func.return_value = True

        self.user = user
        self.user2 = user2
        self.object = object
        self.model = model
        self.request = request
        self.view_func = view_func
        self.test_func = test_func
        self.perm = 'can'
Beispiel #20
0
def test_send_verify_email_change_email(mocker, user):
    """Test email change request verification email sends with a link in it"""
    request = RequestFactory().get(reverse("account-settings"))
    change_request = ChangeEmailRequest.objects.create(
        user=user, new_email="*****@*****.**")

    send_messages_mock = mocker.patch("mail.api.send_messages")

    verification_api.send_verify_email_change_email(request, change_request)

    send_messages_mock.assert_called_once_with([any_instance_of(EmailMessage)])

    url = "{}?verification_code={}".format(
        request.build_absolute_uri(reverse("account-confirm-email-change")),
        quote_plus(change_request.code),
    )

    email_body = send_messages_mock.call_args[0][0][0].body
    assert url in email_body
Beispiel #21
0
    def test_invite_url_sent_triggered_correctly(self, mock_signal,
                                                 sent_invitation_by_user_a,
                                                 user_a):
        invite_url = reverse('invitations:accept-invite',
                             args=[sent_invitation_by_user_a.key])
        request = RequestFactory().get('/')
        invite_url = request.build_absolute_uri(invite_url)

        sent_invitation_by_user_a.send_invitation(request)

        assert mock_signal.called
        assert mock_signal.call_count == 1

        mock_signal.assert_called_with(
            instance=sent_invitation_by_user_a,
            invite_url_sent=invite_url,
            inviter=user_a,
            sender=Invitation,
        )
Beispiel #22
0
    def setUp(self):

        # Параметри, при яких декоратор пропускає до функції:
        user = DummyUser().create_dummy_user(username='******')
        user.has_perms = Mock()
        user.has_perms.return_value = True

        user2 = DummyUser().create_dummy_user(username='******')
        user2.has_perms = Mock()
        user2.has_perms.return_value = True

        root = DummyFolder().create_dummy_root_folder()
        object = DummyFolder().create_dummy_report(root,
                                    id=1, filename='report1', user=user)

        object2 = DummyFolder().create_dummy_report(root,
                                    id=2, filename='report2')

        model = Report

        request = RequestFactory()
        request.build_absolute_uri = Mock()
        request.build_absolute_uri.return_value = "" # path
        request.get_full_path = Mock()
        request.get_full_path.return_value = "" # path
        request.user = user

        view_func = Mock()
        view_func.return_value = 'passed'

        test_func = Mock()
        test_func.return_value = True

        self.user = user
        self.user2 = user2
        self.object = object
        self.model = model
        self.request = request
        self.view_func = view_func
        self.test_func = test_func
        self.perm = 'can'
    def test_refresh_oauth_token(self, mock_get_access_token):
        refresh_token = "refresh-token"
        old_access_token = "old-access-token"
        old_expires = timezone.now() + timedelta(seconds=100)
        new_access_token = "new-access-token"
        new_expires = old_expires + timedelta(seconds=100)

        # mock the get_access_token() function
        mock_get_access_token.return_value = (new_access_token, new_expires,
                                              refresh_token)

        # mock the user and related CanvasOAuth2Token model
        stub_canvas_oauth2_token = StubCanvasOAuth2Token(
            old_access_token, refresh_token, old_expires)
        mock_user = MagicMock()

        # Because of the way mock attributes are stored you can’t directly attach a PropertyMock to a mock object.
        # Instead you can attach it to the mock type object
        type(mock_user).canvas_oauth2_token = PropertyMock(
            return_value=stub_canvas_oauth2_token)

        # initialize request object
        request = RequestFactory().get('/index')
        request.user = mock_user

        # run tests
        actual_oauth_token = refresh_oauth_token(request)

        self.assertEqual(refresh_token, actual_oauth_token.refresh_token)
        self.assertEqual(new_access_token, actual_oauth_token.access_token)
        self.assertEqual(new_expires, actual_oauth_token.expires)

        mock_get_access_token.assert_called_with(
            grant_type='refresh_token',
            client_id=settings.CANVAS_OAUTH_CLIENT_ID,
            client_secret=settings.CANVAS_OAUTH_CLIENT_SECRET,
            redirect_uri=request.build_absolute_uri(
                reverse('canvas-oauth-callback')),
            refresh_token=refresh_token)

        self.assertTrue(stub_canvas_oauth2_token.stub_save_called())
Beispiel #24
0
    def test_invite_url_sent_triggered_correctly(self, mock_signal):
        invite = Invitation.create('*****@*****.**')
        invite_url = reverse('invitations:accept-invite', args=[invite.key])

        request = RequestFactory().get('/')
        request.user = '******'
        invite_url = request.build_absolute_uri(invite_url)

        invite.send_invitation(request)

        self.assertTrue(mock_signal.called)
        self.assertEqual(mock_signal.call_count, 1)

        mock_signal.assert_called_with(
            instance=invite,
            invite_url_sent=invite_url,
            inviter='monkey',
            sender=Invitation,
        )

        invite.delete()
Beispiel #25
0
    def test_invite_url_sent_triggered_correctly(self, mock_signal):
        invite = Invitation.create('*****@*****.**')
        invite_url = reverse('invitations:accept-invite', args=[invite.key])

        request = RequestFactory().get('/')
        request.user = '******'
        invite_url = request.build_absolute_uri(invite_url)

        invite.send_invitation(request)

        self.assertTrue(mock_signal.called)
        self.assertEqual(mock_signal.call_count, 1)

        mock_signal.assert_called_with(
            instance=invite,
            invite_url_sent=invite_url,
            inviter='monkey',
            sender=Invitation,
        )

        invite.delete()
Beispiel #26
0
    def test_invite_url_sent_triggered_correctly(
        self,
        mock_signal,
        sent_invitation_by_user_a,
        user_a,
    ):
        invite_url = reverse(
            app_settings.CONFIRMATION_URL_NAME,
            args=[sent_invitation_by_user_a.key],
        )
        request = RequestFactory().get("/")
        invite_url = request.build_absolute_uri(invite_url)

        sent_invitation_by_user_a.send_invitation(request)

        assert mock_signal.called
        assert mock_signal.call_count == 1

        mock_signal.assert_called_with(
            instance=sent_invitation_by_user_a,
            invite_url_sent=invite_url,
            inviter=user_a,
            sender=Invitation,
        )
Beispiel #27
0
class HydraLinksTestCase(ClearContentTypesTransactionTestCase):
    fixtures = ['projects.json']

    def setUp(self):
        self.user = User.objects.get(username='******')
        self.project = Project.objects.get(slug='emma')
        self.note = Note.objects.create(
            title='A test note',
            project=self.project,
            creator=self.user, last_updater=self.user)

        self.dummy_req = RequestFactory().get('/')

    def test_unauthenticated_hydra_class_request(self):
        """
        An unauthenticated request should only know about a "GET" operation on
        a project item.
        """
        response = self.client.get(
            reverse('api:notes-detail',
                    args=[self.project.slug, self.note.id]),
            HTTP_ACCEPT='application/json')

        self.assertEqual(len(response.data['hydra:operation']), 1)
        self.assertEqual(response.data['hydra:operation'][0]['hydra:method'],
                         'GET')

    def test_authenticated_hydra_class_request(self):
        """
        An authenticated request with sufficient permissions should know about
        "GET", "PUT", and "POST" operations on a project item.
        """
        self.client.login(username='******', password='******')

        response = self.client.get(
            reverse('api:notes-detail',
                    args=[self.project.slug, self.note.id]),
            HTTP_ACCEPT='application/json')

        self.assertEqual(len(response.data['hydra:operation']), 3)
        self.assertEqual(
            [op['hydra:method'] for op in response.data['hydra:operation']],
            ['PUT', 'DELETE', 'GET'])

    def test_authenticated_user_project_home(self):
        """
        The project resource for an authenticated user should show links to
        add items to all projects.
        """
        self.client.login(username='******', password='******')
        response = self.client.get(
            reverse('api:projects-detail', args=[self.project.slug]),
            HTTP_ACCEPT='application/json')

        embedded = response.data.get('embedded')

        self.assertEqual(embedded.keys(), map(
            self.dummy_req.build_absolute_uri,
            [
                '/projects/emma/vocab/#Project/notes',
                '/projects/emma/vocab/#Project/topics',
                '/projects/emma/vocab/#Project/documents',
            ]
        ))

        # FIXME: Should be able to update projects' info in the API
        # self.assertEqual(len(response.data.get('hydra:operation')), 3)
        self.assertEqual(len(response.data.get('hydra:operation')), 1)

        link_class_embeds = [
            hydra_class for hydra_class in embedded.values()
            if hydra_class['@type'] == 'hydra:Link'
        ]

        self.assertEqual(len(link_class_embeds), 3)

        project_url = self.dummy_req.build_absolute_uri(
            self.project.get_absolute_url())
        project_url += 'vocab/#'

        self.assertEqual([
            link_class['hydra:supportedOperation'][0]
            for link_class in link_class_embeds
        ], [
            create_operation(item_type, project_url)
            for item_type in ('Note', 'Topic', 'Document')
        ])

        self.assertEqual(response.data['@context']['notes'], {
            '@id': self.dummy_req.build_absolute_uri(
                '/projects/emma/vocab/#Project/notes'),
            '@type': '@id'
        })

    def test_authenticated_user_home(self):
        self.client.login(username='******', password='******')
        response = self.client.get('/', HTTP_ACCEPT='application/json')

        project_url = self.dummy_req.build_absolute_uri(
            self.project.get_absolute_url())

        self.assertEqual(response.data.get('affiliated_projects').keys(),
                         [project_url])
        self.assertEqual(
            len(response.data['affiliated_projects'].values()[0]['@context']),
            3)
        self.assertEqual(len(response.data.get('embedded')), 3)
Beispiel #28
0
    def test_course_metadata(self, logged_in, enrollment_mode,
                             enable_anonymous,
                             is_microfrontend_enabled_for_user):
        is_microfrontend_enabled_for_user.return_value = True
        check_public_access = mock.Mock()
        check_public_access.return_value = enable_anonymous
        with mock.patch(
                'lms.djangoapps.courseware.access_utils.check_public_access',
                check_public_access):
            if not logged_in:
                self.client.logout()
            if enrollment_mode == 'verified':
                cert = GeneratedCertificateFactory.create(
                    user=self.user,
                    course_id=self.course.id,
                    status='downloadable',
                    mode='verified',
                )
            if enrollment_mode:
                CourseEnrollment.enroll(self.user, self.course.id,
                                        enrollment_mode)

            response = self.client.get(self.url)
            assert response.status_code == 200
            if enrollment_mode:
                enrollment = response.data['enrollment']
                assert enrollment_mode == enrollment['mode']
                assert enrollment['is_active']
                assert len(response.data['tabs']) == 6
                found = False
                for tab in response.data['tabs']:
                    if tab['type'] == 'external_link':
                        assert tab[
                            'url'] != 'http://hidden.com', "Hidden tab is not hidden"
                        if tab['url'] == 'http://zombo.com':
                            found = True
                assert found, 'external link not in course tabs'

                assert not response.data['user_has_passing_grade']
                if enrollment_mode == 'audit':
                    assert response.data['verify_identity_url'] is None
                    assert response.data['verification_status'] == 'none'  # lint-amnesty, pylint: disable=literal-comparison
                    assert response.data['linkedin_add_to_profile_url'] is None
                else:
                    assert response.data['certificate_data'][
                        'cert_status'] == 'earned_but_not_available'
                    expected_verify_identity_url = IDVerificationService.get_verify_location(
                        course_id=self.course.id)
                    # The response contains an absolute URL so this is only checking the path of the final
                    assert expected_verify_identity_url in response.data[
                        'verify_identity_url']
                    assert response.data['verification_status'] == 'none'  # lint-amnesty, pylint: disable=literal-comparison

                    request = RequestFactory().request()
                    cert_url = get_certificate_url(course_id=self.course.id,
                                                   uuid=cert.verify_uuid)
                    linkedin_url_params = {
                        'name':
                        '{platform_name} Verified Certificate for {course_name}'
                        .format(
                            platform_name=settings.PLATFORM_NAME,
                            course_name=self.course.display_name,
                        ),
                        'certUrl':
                        request.build_absolute_uri(cert_url),
                        # default value from the LinkedInAddToProfileConfigurationFactory company_identifier
                        'organizationId':
                        1337,
                        'certId':
                        cert.verify_uuid,
                        'issueYear':
                        cert.created_date.year,
                        'issueMonth':
                        cert.created_date.month,
                    }
                    expected_linkedin_url = (
                        'https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME&{params}'
                        .format(params=urlencode(linkedin_url_params)))
                    assert response.data[
                        'linkedin_add_to_profile_url'] == expected_linkedin_url
            elif enable_anonymous and not logged_in:
                # multiple checks use this handler
                check_public_access.assert_called()
                assert response.data['enrollment']['mode'] is None
                assert response.data['course_access']['has_access']
            else:
                assert not response.data['course_access']['has_access']
class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
    """
    Tests for the certificates web/html views
    """
    def setUp(self):
        super(CertificatesViewsTests, self).setUp()
        self.client = Client()
        self.course = CourseFactory.create(
            org='testorg', number='run1', display_name='refundable course'
        )
        self.course_id = self.course.location.course_key
        self.user = UserFactory.create(
            email='*****@*****.**',
            username='******',
            password='******'
        )
        self.user.profile.name = "Joe User"
        self.user.profile.save()
        self.client.login(username=self.user.username, password='******')
        self.request = RequestFactory().request()

        self.cert = GeneratedCertificate.objects.create(
            user=self.user,
            course_id=self.course_id,
            verify_uuid=uuid4(),
            download_uuid=uuid4(),
            download_url="http://www.example.com/certificates/download",
            grade="0.95",
            key='the_key',
            distinction=True,
            status='generated',
            mode='honor',
            name=self.user.profile.name,
        )
        CourseEnrollmentFactory.create(
            user=self.user,
            course_id=self.course_id
        )
        CertificateHtmlViewConfigurationFactory.create()
        LinkedInAddToProfileConfigurationFactory.create()

    def _add_course_certificates(self, count=1, signatory_count=0, is_active=True):
        """
        Create certificate for the course.
        """
        signatories = [
            {
                'name': 'Signatory_Name ' + str(i),
                'title': 'Signatory_Title ' + str(i),
                'organization': 'Signatory_Organization ' + str(i),
                'signature_image_path': '/static/certificates/images/demo-sig{}.png'.format(i),
                'id': i
            } for i in xrange(signatory_count)

        ]

        certificates = [
            {
                'id': i,
                'name': 'Name ' + str(i),
                'description': 'Description ' + str(i),
                'course_title': 'course_title_' + str(i),
                'org_logo_path': '/t4x/orgX/testX/asset/org-logo-{}.png'.format(i),
                'signatories': signatories,
                'version': 1,
                'is_active': is_active
            } for i in xrange(count)
        ]

        self.course.certificates = {'certificates': certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)

    def _create_custom_template(self, org_id=None, mode=None, course_key=None):
        """
        Creates a custom certificate template entry in DB.
        """
        template_html = """
            <html>
            <body>
                lang: ${LANGUAGE_CODE}
                course name: ${accomplishment_copy_course_name}
                mode: ${course_mode}
                ${accomplishment_copy_course_description}
                ${twitter_url}
            </body>
            </html>
        """
        template = CertificateTemplate(
            name='custom template',
            template=template_html,
            organization_id=org_id,
            course_key=course_key,
            mode=mode,
            is_active=True
        )
        template.save()

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_linkedin_share_url(self):
        """
        Test: LinkedIn share URL.
        """
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertTrue(urllib.quote_plus(self.request.build_absolute_uri(test_url)) in response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_rendering_course_organization_data(self):
        """
        Test: organization data should render on certificate web view if course has organization.
        """
        test_organization_data = {
            'name': 'test organization',
            'short_name': 'test_organization',
            'description': 'Test Organization Description',
            'active': True,
            'logo': '/logo_test1.png/'
        }
        test_org = organizations_api.add_organization(organization_data=test_organization_data)
        organizations_api.add_organization_course(organization_data=test_org, course_id=unicode(self.course.id))
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn(
            'a course of study offered by test_organization, an online learning initiative of test organization',
            response.content
        )
        self.assertNotIn(
            'a course of study offered by testorg',
            response.content
        )
        self.assertIn(
            '<title>test_organization {} Certificate |'.format(self.course.number, ),
            response.content
        )
        self.assertIn('logo_test1.png', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_valid_certificate(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self._add_course_certificates(count=1, signatory_count=2)
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Hit any "verified" mode-specific branches
        self.cert.mode = 'verified'
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Hit any 'xseries' mode-specific branches
        self.cert.mode = 'xseries'
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_valid_signatories(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self._add_course_certificates(count=1, signatory_count=2)
        response = self.client.get(test_url)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Name 0', response.content)
        self.assertIn('Signatory_Title 0', response.content)
        self.assertIn('Signatory_Organization 0', response.content)
        self.assertIn('/static/certificates/images/demo-sig0.png', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_course_display_name_not_override_with_course_title(self):
        # if certificate in descriptor has not course_title then course name should not be overridden with this title.
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        test_certificates = [
            {
                'id': 0,
                'name': 'Name 0',
                'description': 'Description 0',
                'signatories': [],
                'version': 1,
                'is_active':True
            }
        ]
        self.course.certificates = {'certificates': test_certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)
        response = self.client.get(test_url)
        self.assertNotIn('test_course_title_0', response.content)
        self.assertIn('refundable course', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_course_display_overrides(self):
        """
        Tests if `Course Number Display String` or `Course Organization Display` is set for a course
        in advance settings
        Then web certificate should display that course number and course org set in advance
        settings instead of original course number and course org.
        """
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self._add_course_certificates(count=1, signatory_count=2)
        self.course.display_coursenumber = "overridden_number"
        self.course.display_organization = "overridden_org"
        self.store.update_item(self.course, self.user.id)

        response = self.client.get(test_url)
        self.assertIn('overridden_number', response.content)
        self.assertIn('overridden_org', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_view_without_org_logo(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        test_certificates = [
            {
                'id': 0,
                'name': 'Certificate Name 0',
                'signatories': [],
                'version': 1,
                'is_active': True
            }
        ]
        self.course.certificates = {'certificates': test_certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)
        response = self.client.get(test_url)
        # make sure response html has only one organization logo container for edX
        self.assertContains(response, "<li class=\"wrapper-organization\">", 1)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_without_signatories(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course)
        )
        self._add_course_certificates(count=1, signatory_count=0)
        response = self.client.get(test_url)
        self.assertNotIn('Signatory_Name 0', response.content)
        self.assertNotIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    def test_render_html_view_disabled_feature_flag_returns_static_url(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self.assertIn(str(self.cert.download_url), test_url)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_course_id(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id='az/23423/4vs'
        )

        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_course(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id='missing/course/key'
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_user(self):
        test_url = get_certificate_url(
            user_id=111,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_user_certificate(self):
        self.cert.delete()
        self.assertEqual(len(GeneratedCertificate.objects.all()), 0)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_preview_mode(self):
        """
        test certificate web view should render properly along with its signatories information when accessing it in
        preview mode. Either the certificate is marked active or not.
        """
        self.cert.delete()
        self.assertEqual(len(GeneratedCertificate.objects.all()), 0)
        self._add_course_certificates(count=1, signatory_count=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url + '?preview=honor')
        #accessing certificate web view in preview mode without
        # staff or instructor access should show invalid certificate
        self.assertIn('Cannot Find Certificate', response.content)

        CourseStaffRole(self.course.id).add_users(self.user)

        response = self.client.get(test_url + '?preview=honor')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

        # mark certificate inactive but accessing in preview mode.
        self._add_course_certificates(count=1, signatory_count=2, is_active=False)
        response = self.client.get(test_url + '?preview=honor')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_preview_mode_when_user_already_has_cert(self):
        """
        test certificate web view should render properly in
        preview mode even if user who is previewing already has a certificate
        generated with different mode.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        CourseStaffRole(self.course.id).add_users(self.user)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        # user has already has certificate generated for 'honor' mode
        # so let's try to preview in 'verified' mode.
        response = self.client.get(test_url + '?preview=verified')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_certificate_configuration(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn("Invalid Certificate", response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_500_view_invalid_certificate_configuration(self):
        CertificateHtmlViewConfiguration.objects.all().update(enabled=False)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn("Invalid Certificate Configuration", response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_evidence_event_emitted(self):
        self.client.logout()
        self._add_course_certificates(count=1, signatory_count=2)
        self.recreate_tracker()
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        actual_event = self.get_event()
        self.assertEqual(actual_event['name'], 'edx.certificate.evidence_visited')
        assert_event_matches(
            {
                'user_id': self.user.id,
                'certificate_id': unicode(self.cert.verify_uuid),
                'enrollment_mode': self.cert.mode,
                'certificate_url': test_url,
                'course_id': unicode(self.course.id),
                'social_network': CertificateSocialNetworks.linkedin
            },
            actual_event['data']
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_evidence_event_sent(self):
        cert_url = get_certificate_url(
            user_id=self.user.id,
            course_id=self.course_id
        )
        test_url = '{}?evidence_visit=1'.format(cert_url)
        self._add_course_certificates(count=1, signatory_count=2)
        self.recreate_tracker()
        assertion = BadgeAssertion(
            user=self.user, course_id=self.course_id, mode='honor',
            data={
                'image': 'http://www.example.com/image.png',
                'json': {'id': 'http://www.example.com/assertion.json'},
                'issuer': 'http://www.example.com/issuer.json',

            }
        )
        assertion.save()
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        assert_event_matches(
            {
                'name': 'edx.badge.assertion.evidence_visited',
                'data': {
                    'course_id': 'testorg/run1/refundable_course',
                    # pylint: disable=no-member
                    'assertion_id': assertion.id,
                    'assertion_json_url': 'http://www.example.com/assertion.json',
                    'assertion_image_url': 'http://www.example.com/image.png',
                    'user_id': self.user.id,
                    'issuer': 'http://www.example.com/issuer.json',
                    'enrollment_mode': 'honor',
                },
            },
            self.get_event()
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    def test_request_certificate_without_passing(self):
        self.cert.status = CertificateStatuses.unavailable
        self.cert.save()
        request_certificate_url = reverse('certificates.views.request_certificate')
        response = self.client.post(request_certificate_url, {'course_id': unicode(self.course.id)})
        self.assertEqual(response.status_code, 200)
        response_json = json.loads(response.content)
        self.assertEqual(CertificateStatuses.notpassing, response_json['add_status'])

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    @override_settings(CERT_QUEUE='test-queue')
    def test_request_certificate_after_passing(self):
        self.cert.status = CertificateStatuses.unavailable
        self.cert.save()
        request_certificate_url = reverse('certificates.views.request_certificate')
        with patch('capa.xqueue_interface.XQueueInterface.send_to_queue') as mock_queue:
            mock_queue.return_value = (0, "Successfully queued")
            with patch('courseware.grades.grade') as mock_grade:
                mock_grade.return_value = {'grade': 'Pass', 'percent': 0.75}
                response = self.client.post(request_certificate_url, {'course_id': unicode(self.course.id)})
                self.assertEqual(response.status_code, 200)
                response_json = json.loads(response.content)
                self.assertEqual(CertificateStatuses.generating, response_json['add_status'])

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    @override_settings(LANGUAGE_CODE='fr')
    def test_certificate_custom_template_with_org_mode_course(self):
        """
        Tests custom template search and rendering.
        This test should check template matching when org={org}, course={course}, mode={mode}.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(org_id=1, mode='honor', course_key=unicode(self.course.id))
        self._create_custom_template(org_id=2, mode='honor')
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 1, "name": "organization name"}],
                [{"id": 2, "name": "organization name 2"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'lang: fr')
            self.assertContains(response, 'course name: course_title_0')
            # test with second organization template
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'lang: fr')
            self.assertContains(response, 'course name: course_title_0')

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_org(self):
        """
        Tests custom template search if we have a single template for organization and mode
        with course set to Null.
        This test should check template matching when org={org}, course=Null, mode={mode}.
        """
        course = CourseFactory.create(
            org='cstX', number='cst_22', display_name='custom template course'
        )

        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(org_id=1, mode='honor')
        self._create_custom_template(org_id=1, mode='honor', course_key=course.id)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 1, "name": "organization name"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'course name: course_title_0')

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_organization(self):
        """
        Tests custom template search when we have a single template for a organization.
        This test should check template matching when org={org}, course=Null, mode=null.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(org_id=1, mode='honor')
        self._create_custom_template(org_id=1, mode='honor', course_key=self.course.id)
        self._create_custom_template(org_id=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 2, "name": "organization name 2"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_course_mode(self):
        """
        Tests custom template search if we have a single template for a course mode.
        This test should check template matching when org=null, course=Null, mode={mode}.
        """
        mode = 'honor'
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(mode=mode)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.return_value = []
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'mode: {}'.format(mode))

    @ddt.data(True, False)
    def test_certificate_custom_template_with_unicode_data(self, custom_certs_enabled):
        """
        Tests custom template renders properly with unicode data.
        """
        mode = 'honor'
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(mode=mode)
        with patch.dict("django.conf.settings.FEATURES", {
            "CERTIFICATES_HTML_VIEW": True,
            "CUSTOM_CERTIFICATE_TEMPLATES_ENABLED": custom_certs_enabled
        }):
            test_url = get_certificate_url(
                user_id=self.user.id,
                course_id=unicode(self.course.id)
            )
            with patch.dict("django.conf.settings.SOCIAL_SHARING_SETTINGS", {
                "CERTIFICATE_TWITTER": True,
                "CERTIFICATE_TWITTER_TEXT": u"nền tảng học tập"
            }):
                with patch('django.http.HttpRequest.build_absolute_uri') as mock_abs_uri:
                    mock_abs_uri.return_value = '='.join(['http://localhost/?param', u'é'])
                    with patch('certificates.api.get_course_organizations') as mock_get_orgs:
                        mock_get_orgs.return_value = []
                        response = self.client.get(test_url)
                        self.assertEqual(response.status_code, 200)
                        if custom_certs_enabled:
                            self.assertContains(response, 'mode: {}'.format(mode))
                        else:
                            self.assertContains(response, "Tweet this Accomplishment")
                        self.assertContains(response, 'https://twitter.com/intent/tweet')
Beispiel #30
0
    def test_enrolled_course_metadata(self, logged_in, enrollment_mode):
        check_public_access = mock.Mock()
        check_public_access.return_value = ACCESS_DENIED
        with mock.patch('lms.djangoapps.courseware.access_utils.check_public_access', check_public_access):
            if not logged_in:
                self.client.logout()
            if enrollment_mode == 'verified':
                cert = GeneratedCertificateFactory.create(
                    user=self.user,
                    course_id=self.course.id,
                    status='downloadable',
                    mode='verified',
                )
            if enrollment_mode:
                CourseEnrollment.enroll(self.user, self.course.id, enrollment_mode)

            response = self.client.get(self.url)
            assert response.status_code == 200

            enrollment = response.data['enrollment']
            assert enrollment_mode == enrollment['mode']
            assert enrollment['is_active']

            assert not response.data['user_has_passing_grade']
            assert response.data['celebrations']['first_section']
            assert not response.data['celebrations']['weekly_goal']

            # This import errors in cms if it is imported at the top level
            from lms.djangoapps.course_goals.api import get_course_goal
            selected_goal = get_course_goal(self.user, self.course.id)
            if selected_goal:
                assert response.data['course_goals']['selected_goal'] == {
                    'days_per_week': selected_goal.days_per_week,
                    'subscribed_to_reminders': selected_goal.subscribed_to_reminders,
                }

            if enrollment_mode == 'audit':
                assert response.data['verify_identity_url'] is None
                assert response.data['verification_status'] == 'none'
                assert response.data['linkedin_add_to_profile_url'] is None
            else:
                assert response.data['certificate_data']['cert_status'] == 'earned_but_not_available'
                expected_verify_identity_url = IDVerificationService.get_verify_location(
                    course_id=self.course.id
                )
                # The response contains an absolute URL so this is only checking the path of the final
                assert expected_verify_identity_url in response.data['verify_identity_url']
                assert response.data['verification_status'] == 'none'

                request = RequestFactory().request()
                cert_url = get_certificate_url(course_id=self.course.id, uuid=cert.verify_uuid)
                linkedin_url_params = {
                    'name': '{platform_name} Verified Certificate for {course_name}'.format(
                        platform_name=settings.PLATFORM_NAME, course_name=self.course.display_name,
                    ),
                    'certUrl': request.build_absolute_uri(cert_url),
                    # default value from the LinkedInAddToProfileConfigurationFactory company_identifier
                    'organizationId': 1337,
                    'certId': cert.verify_uuid,
                    'issueYear': cert.created_date.year,
                    'issueMonth': cert.created_date.month,
                }
                expected_linkedin_url = (
                    'https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME&{params}'.format(
                        params=urlencode(linkedin_url_params)
                    )
                )
                assert response.data['linkedin_add_to_profile_url'] == expected_linkedin_url
class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
    """
    Tests for the certificates web/html views
    """
    def setUp(self):
        super(CertificatesViewsTests, self).setUp()
        self.client = Client()
        self.course = CourseFactory.create(
            org='testorg', number='run1', display_name='refundable course'
        )
        self.course_id = self.course.location.course_key
        self.user = UserFactory.create(
            email='*****@*****.**',
            username='******',
            password='******'
        )
        self.user.profile.name = "Joe User"
        self.user.profile.save()
        self.client.login(username=self.user.username, password='******')
        self.request = RequestFactory().request()

        self.cert = GeneratedCertificate.objects.create(
            user=self.user,
            course_id=self.course_id,
            verify_uuid=uuid4(),
            download_uuid=uuid4(),
            download_url="http://www.example.com/certificates/download",
            grade="0.95",
            key='the_key',
            distinction=True,
            status='generated',
            mode='honor',
            name=self.user.profile.name,
        )
        CourseEnrollmentFactory.create(
            user=self.user,
            course_id=self.course_id
        )
        CertificateHtmlViewConfigurationFactory.create()
        LinkedInAddToProfileConfigurationFactory.create()

    def _add_course_certificates(self, count=1, signatory_count=0, is_active=True):
        """
        Create certificate for the course.
        """
        signatories = [
            {
                'name': 'Signatory_Name ' + str(i),
                'title': 'Signatory_Title ' + str(i),
                'organization': 'Signatory_Organization ' + str(i),
                'signature_image_path': '/static/certificates/images/demo-sig{}.png'.format(i),
                'id': i
            } for i in xrange(signatory_count)

        ]

        certificates = [
            {
                'id': i,
                'name': 'Name ' + str(i),
                'description': 'Description ' + str(i),
                'course_title': 'course_title_' + str(i),
                'org_logo_path': '/t4x/orgX/testX/asset/org-logo-{}.png'.format(i),
                'signatories': signatories,
                'version': 1,
                'is_active': is_active
            } for i in xrange(count)
        ]

        self.course.certificates = {'certificates': certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)

    def _create_custom_template(self, org_id=None, mode=None, course_key=None):
        """
        Creates a custom certificate template entry in DB.
        """
        template_html = """
            <html>
            <body>
                lang: ${LANGUAGE_CODE}
                course name: ${accomplishment_copy_course_name}
                mode: ${course_mode}
                ${accomplishment_copy_course_description}
                ${twitter_url}
            </body>
            </html>
        """
        template = CertificateTemplate(
            name='custom template',
            template=template_html,
            organization_id=org_id,
            course_key=course_key,
            mode=mode,
            is_active=True
        )
        template.save()

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_linkedin_share_url(self):
        """
        Test: LinkedIn share URL.
        """
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn(urllib.quote_plus(self.request.build_absolute_uri(test_url)), response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    @mock.patch("microsite_configuration.microsite.is_request_in_microsite", _fake_is_request_in_microsite)
    def test_linkedin_share_microsites(self):
        """
        Test: LinkedIn share URL should not be visible when called from within a microsite (for now)
        """
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)

        # the URL should not be present
        self.assertNotIn(urllib.quote_plus(self.request.build_absolute_uri(test_url)), response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_rendering_course_organization_data(self):
        """
        Test: organization data should render on certificate web view if course has organization.
        """
        test_organization_data = {
            'name': 'test organization',
            'short_name': 'test_organization',
            'description': 'Test Organization Description',
            'active': True,
            'logo': '/logo_test1.png/'
        }
        test_org = organizations_api.add_organization(organization_data=test_organization_data)
        organizations_api.add_organization_course(organization_data=test_org, course_id=unicode(self.course.id))
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn(
            'a course of study offered by test_organization, an online learning initiative of test organization',
            response.content
        )
        self.assertNotIn(
            'a course of study offered by testorg',
            response.content
        )
        self.assertIn(
            '<title>test_organization {} Certificate |'.format(self.course.number, ),
            response.content
        )
        self.assertIn('logo_test1.png', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_valid_certificate(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self._add_course_certificates(count=1, signatory_count=2)
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Hit any "verified" mode-specific branches
        self.cert.mode = 'verified'
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Hit any 'xseries' mode-specific branches
        self.cert.mode = 'xseries'
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_valid_signatories(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self._add_course_certificates(count=1, signatory_count=2)
        response = self.client.get(test_url)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Name 0', response.content)
        self.assertIn('Signatory_Title 0', response.content)
        self.assertIn('Signatory_Organization 0', response.content)
        self.assertIn('/static/certificates/images/demo-sig0.png', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_course_display_name_not_override_with_course_title(self):
        # if certificate in descriptor has not course_title then course name should not be overridden with this title.
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        test_certificates = [
            {
                'id': 0,
                'name': 'Name 0',
                'description': 'Description 0',
                'signatories': [],
                'version': 1,
                'is_active':True
            }
        ]
        self.course.certificates = {'certificates': test_certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)
        response = self.client.get(test_url)
        self.assertNotIn('test_course_title_0', response.content)
        self.assertIn('refundable course', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_course_display_overrides(self):
        """
        Tests if `Course Number Display String` or `Course Organization Display` is set for a course
        in advance settings
        Then web certificate should display that course number and course org set in advance
        settings instead of original course number and course org.
        """
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self._add_course_certificates(count=1, signatory_count=2)
        self.course.display_coursenumber = "overridden_number"
        self.course.display_organization = "overridden_org"
        self.store.update_item(self.course, self.user.id)

        response = self.client.get(test_url)
        self.assertIn('overridden_number', response.content)
        self.assertIn('overridden_org', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_view_without_org_logo(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        test_certificates = [
            {
                'id': 0,
                'name': 'Certificate Name 0',
                'signatories': [],
                'version': 1,
                'is_active': True
            }
        ]
        self.course.certificates = {'certificates': test_certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)
        response = self.client.get(test_url)
        # make sure response html has only one organization logo container for edX
        self.assertContains(response, "<li class=\"wrapper-organization\">", 1)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_without_signatories(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course)
        )
        self._add_course_certificates(count=1, signatory_count=0)
        response = self.client.get(test_url)
        self.assertNotIn('Signatory_Name 0', response.content)
        self.assertNotIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    def test_render_html_view_disabled_feature_flag_returns_static_url(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self.assertIn(str(self.cert.download_url), test_url)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_course_id(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id='az/23423/4vs'
        )

        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_course(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id='missing/course/key'
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_user(self):
        test_url = get_certificate_url(
            user_id=111,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_user_certificate(self):
        self.cert.delete()
        self.assertEqual(len(GeneratedCertificate.objects.all()), 0)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_preview_mode(self):
        """
        test certificate web view should render properly along with its signatories information when accessing it in
        preview mode. Either the certificate is marked active or not.
        """
        self.cert.delete()
        self.assertEqual(len(GeneratedCertificate.objects.all()), 0)
        self._add_course_certificates(count=1, signatory_count=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url + '?preview=honor')
        #accessing certificate web view in preview mode without
        # staff or instructor access should show invalid certificate
        self.assertIn('Cannot Find Certificate', response.content)

        CourseStaffRole(self.course.id).add_users(self.user)

        response = self.client.get(test_url + '?preview=honor')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

        # mark certificate inactive but accessing in preview mode.
        self._add_course_certificates(count=1, signatory_count=2, is_active=False)
        response = self.client.get(test_url + '?preview=honor')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_preview_mode_when_user_already_has_cert(self):
        """
        test certificate web view should render properly in
        preview mode even if user who is previewing already has a certificate
        generated with different mode.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        CourseStaffRole(self.course.id).add_users(self.user)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        # user has already has certificate generated for 'honor' mode
        # so let's try to preview in 'verified' mode.
        response = self.client.get(test_url + '?preview=verified')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_certificate_configuration(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn("Invalid Certificate", response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_500_view_invalid_certificate_configuration(self):
        CertificateHtmlViewConfiguration.objects.all().update(enabled=False)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url + "?preview=honor")
        self.assertIn("Invalid Certificate Configuration", response.content)

        # Verify that Exception is raised when certificate is not in the preview mode
        with self.assertRaises(Exception):
            self.client.get(test_url)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_evidence_event_emitted(self):
        self.client.logout()
        self._add_course_certificates(count=1, signatory_count=2)
        self.recreate_tracker()
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        actual_event = self.get_event()
        self.assertEqual(actual_event['name'], 'edx.certificate.evidence_visited')
        assert_event_matches(
            {
                'user_id': self.user.id,
                'certificate_id': unicode(self.cert.verify_uuid),
                'enrollment_mode': self.cert.mode,
                'certificate_url': test_url,
                'course_id': unicode(self.course.id),
                'social_network': CertificateSocialNetworks.linkedin
            },
            actual_event['data']
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_evidence_event_sent(self):
        cert_url = get_certificate_url(
            user_id=self.user.id,
            course_id=self.course_id
        )
        test_url = '{}?evidence_visit=1'.format(cert_url)
        self._add_course_certificates(count=1, signatory_count=2)
        self.recreate_tracker()
        assertion = BadgeAssertion(
            user=self.user, course_id=self.course_id, mode='honor',
            data={
                'image': 'http://www.example.com/image.png',
                'json': {'id': 'http://www.example.com/assertion.json'},
                'issuer': 'http://www.example.com/issuer.json',

            }
        )
        assertion.save()
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        assert_event_matches(
            {
                'name': 'edx.badge.assertion.evidence_visited',
                'data': {
                    'course_id': 'testorg/run1/refundable_course',
                    # pylint: disable=no-member
                    'assertion_id': assertion.id,
                    'assertion_json_url': 'http://www.example.com/assertion.json',
                    'assertion_image_url': 'http://www.example.com/image.png',
                    'user_id': self.user.id,
                    'issuer': 'http://www.example.com/issuer.json',
                    'enrollment_mode': 'honor',
                },
            },
            self.get_event()
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    def test_request_certificate_without_passing(self):
        self.cert.status = CertificateStatuses.unavailable
        self.cert.save()
        request_certificate_url = reverse('certificates.views.request_certificate')
        response = self.client.post(request_certificate_url, {'course_id': unicode(self.course.id)})
        self.assertEqual(response.status_code, 200)
        response_json = json.loads(response.content)
        self.assertEqual(CertificateStatuses.notpassing, response_json['add_status'])

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    @override_settings(CERT_QUEUE='test-queue')
    def test_request_certificate_after_passing(self):
        self.cert.status = CertificateStatuses.unavailable
        self.cert.save()
        request_certificate_url = reverse('certificates.views.request_certificate')
        with patch('capa.xqueue_interface.XQueueInterface.send_to_queue') as mock_queue:
            mock_queue.return_value = (0, "Successfully queued")
            with patch('courseware.grades.grade') as mock_grade:
                mock_grade.return_value = {'grade': 'Pass', 'percent': 0.75}
                response = self.client.post(request_certificate_url, {'course_id': unicode(self.course.id)})
                self.assertEqual(response.status_code, 200)
                response_json = json.loads(response.content)
                self.assertEqual(CertificateStatuses.generating, response_json['add_status'])

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    @override_settings(LANGUAGE_CODE='fr')
    def test_certificate_custom_template_with_org_mode_course(self):
        """
        Tests custom template search and rendering.
        This test should check template matching when org={org}, course={course}, mode={mode}.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(org_id=1, mode='honor', course_key=unicode(self.course.id))
        self._create_custom_template(org_id=2, mode='honor')
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 1, "name": "organization name"}],
                [{"id": 2, "name": "organization name 2"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'lang: fr')
            self.assertContains(response, 'course name: course_title_0')
            # test with second organization template
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'lang: fr')
            self.assertContains(response, 'course name: course_title_0')

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_org(self):
        """
        Tests custom template search if we have a single template for organization and mode
        with course set to Null.
        This test should check template matching when org={org}, course=Null, mode={mode}.
        """
        course = CourseFactory.create(
            org='cstX', number='cst_22', display_name='custom template course'
        )

        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(org_id=1, mode='honor')
        self._create_custom_template(org_id=1, mode='honor', course_key=course.id)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 1, "name": "organization name"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'course name: course_title_0')

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_organization(self):
        """
        Tests custom template search when we have a single template for a organization.
        This test should check template matching when org={org}, course=Null, mode=null.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(org_id=1, mode='honor')
        self._create_custom_template(org_id=1, mode='honor', course_key=self.course.id)
        self._create_custom_template(org_id=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 2, "name": "organization name 2"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_course_mode(self):
        """
        Tests custom template search if we have a single template for a course mode.
        This test should check template matching when org=null, course=Null, mode={mode}.
        """
        mode = 'honor'
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(mode=mode)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.return_value = []
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'mode: {}'.format(mode))

    @ddt.data(True, False)
    def test_certificate_custom_template_with_unicode_data(self, custom_certs_enabled):
        """
        Tests custom template renders properly with unicode data.
        """
        mode = 'honor'
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(mode=mode)
        with patch.dict("django.conf.settings.FEATURES", {
            "CERTIFICATES_HTML_VIEW": True,
            "CUSTOM_CERTIFICATE_TEMPLATES_ENABLED": custom_certs_enabled
        }):
            test_url = get_certificate_url(
                user_id=self.user.id,
                course_id=unicode(self.course.id)
            )
            with patch.dict("django.conf.settings.SOCIAL_SHARING_SETTINGS", {
                "CERTIFICATE_TWITTER": True,
                "CERTIFICATE_TWITTER_TEXT": u"nền tảng học tập"
            }):
                with patch('django.http.HttpRequest.build_absolute_uri') as mock_abs_uri:
                    mock_abs_uri.return_value = '='.join(['http://localhost/?param', u'é'])
                    with patch('certificates.api.get_course_organizations') as mock_get_orgs:
                        mock_get_orgs.return_value = []
                        response = self.client.get(test_url)
                        self.assertEqual(response.status_code, 200)
                        if custom_certs_enabled:
                            self.assertContains(response, 'mode: {}'.format(mode))
                        else:
                            self.assertContains(response, "Tweet this Accomplishment")
                        self.assertContains(response, 'https://twitter.com/intent/tweet')
Beispiel #32
0
def test_invalid_page_param():
    url = "%s?%s" % (reverse("search"), "page=a")
    request = RequestFactory().get(url)
    queryset = list(range(100))
    paginated = paginate(request, queryset)
    eq_(paginated.url, request.build_absolute_uri(request.path) + "?")
Beispiel #33
0
class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
    """
    Tests for the certificates web/html views
    """
    def setUp(self):
        super(CertificatesViewsTests, self).setUp()
        self.client = Client()
        self.course = CourseFactory.create(org='testorg',
                                           number='run1',
                                           display_name='refundable course')
        self.course_id = self.course.location.course_key
        self.user = UserFactory.create(email='*****@*****.**',
                                       username='******',
                                       password='******')
        self.user.profile.name = "Joe User"
        self.user.profile.save()
        self.client.login(username=self.user.username, password='******')
        self.request = RequestFactory().request()

        self.cert = GeneratedCertificate.objects.create(
            user=self.user,
            course_id=self.course_id,
            verify_uuid=uuid4(),
            download_uuid=uuid4(),
            download_url="http://www.example.com/certificates/download",
            grade="0.95",
            key='the_key',
            distinction=True,
            status='generated',
            mode='honor',
            name=self.user.profile.name,
        )
        CourseEnrollmentFactory.create(user=self.user,
                                       course_id=self.course_id)
        CertificateHtmlViewConfigurationFactory.create()
        LinkedInAddToProfileConfigurationFactory.create()

    def _add_course_certificates(self,
                                 count=1,
                                 signatory_count=0,
                                 is_active=True):
        """
        Create certificate for the course.
        """
        signatories = [{
            'name':
            'Signatory_Name ' + str(i),
            'title':
            'Signatory_Title ' + str(i),
            'organization':
            'Signatory_Organization ' + str(i),
            'signature_image_path':
            '/static/certificates/images/demo-sig{}.png'.format(i),
            'id':
            i,
        } for i in xrange(0, signatory_count)]

        certificates = [{
            'id':
            i,
            'name':
            'Name ' + str(i),
            'description':
            'Description ' + str(i),
            'course_title':
            'course_title_' + str(i),
            'org_logo_path':
            '/t4x/orgX/testX/asset/org-logo-{}.png'.format(i),
            'signatories':
            signatories,
            'version':
            1,
            'is_active':
            is_active
        } for i in xrange(0, count)]

        self.course.certificates = {'certificates': certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)

    def _create_custom_template(self, org_id=None, mode=None, course_key=None):
        """
        Creates a custom certificate template entry in DB.
        """
        template_html = """
            <html>
            <body>
                lang: ${LANGUAGE_CODE}
                course name: ${accomplishment_copy_course_name}
                mode: ${course_mode}
                ${accomplishment_copy_course_description}
            </body>
            </html>
        """
        template = CertificateTemplate(name='custom template',
                                       template=template_html,
                                       organization_id=org_id,
                                       course_key=course_key,
                                       mode=mode,
                                       is_active=True)
        template.save()

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_linkedin_share_url(self):
        """
        Test: LinkedIn share URL.
        """
        self._add_course_certificates(count=1,
                                      signatory_count=1,
                                      is_active=True)
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        response = self.client.get(test_url)
        self.assertTrue(
            urllib.quote_plus(self.request.build_absolute_uri(test_url)) in
            response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_rendering_course_organization_data(self):
        """
        Test: organization data should render on certificate web view if course has organization.
        """
        test_organization_data = {
            'name': 'test organization',
            'short_name': 'test_organization',
            'description': 'Test Organization Description',
            'active': True,
            'logo': '/logo_test1.png/'
        }
        test_org = organizations_api.add_organization(
            organization_data=test_organization_data)
        organizations_api.add_organization_course(organization_data=test_org,
                                                  course_id=unicode(
                                                      self.course.id))
        self._add_course_certificates(count=1,
                                      signatory_count=1,
                                      is_active=True)
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        response = self.client.get(test_url)
        self.assertIn(
            'a course of study offered by test_organization, an online learning initiative of test organization',
            response.content)
        self.assertNotIn('a course of study offered by testorg',
                         response.content)
        self.assertIn(
            '<title>test_organization {} Certificate |'.format(
                self.course.number, ), response.content)
        self.assertIn('logo_test1.png', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_valid_certificate(self):
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        self._add_course_certificates(count=1, signatory_count=2)
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Hit any "verified" mode-specific branches
        self.cert.mode = 'verified'
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Hit any 'xseries' mode-specific branches
        self.cert.mode = 'xseries'
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_valid_signatories(self):
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        self._add_course_certificates(count=1, signatory_count=2)
        response = self.client.get(test_url)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Name 0', response.content)
        self.assertIn('Signatory_Title 0', response.content)
        self.assertIn('Signatory_Organization 0', response.content)
        self.assertIn('/static/certificates/images/demo-sig0.png',
                      response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_course_display_name_not_override_with_course_title(self):
        # if certificate in descriptor has not course_title then course name should not be overridden with this title.
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        test_certificates = [{
            'id': 0,
            'name': 'Name 0',
            'description': 'Description 0',
            'signatories': [],
            'version': 1,
            'is_active': True
        }]
        self.course.certificates = {'certificates': test_certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)
        response = self.client.get(test_url)
        self.assertNotIn('test_course_title_0', response.content)
        self.assertIn('refundable course', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_view_without_org_logo(self):
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        test_certificates = [{
            'id': 0,
            'name': 'Certificate Name 0',
            'signatories': [],
            'version': 1,
            'is_active': True
        }]
        self.course.certificates = {'certificates': test_certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)
        response = self.client.get(test_url)
        # make sure response html has only one organization logo container for edX
        self.assertContains(response, "<li class=\"wrapper-organization\">", 1)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_without_signatories(self):
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course))
        self._add_course_certificates(count=1, signatory_count=0)
        response = self.client.get(test_url)
        self.assertNotIn('Signatory_Name 0', response.content)
        self.assertNotIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    def test_render_html_view_disabled_feature_flag_returns_static_url(self):
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        self.assertIn(str(self.cert.download_url), test_url)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_course_id(self):
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id='az/23423/4vs')

        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_course(self):
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id='missing/course/key')
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_user(self):
        test_url = get_certificate_url(user_id=111,
                                       course_id=unicode(self.course.id))
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_user_certificate(self):
        self.cert.delete()
        self.assertEqual(len(GeneratedCertificate.objects.all()), 0)
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_preview_mode(self):
        """
        test certificate web view should render properly along with its signatories information when accessing it in
        preview mode. Either the certificate is marked active or not.
        """
        self.cert.delete()
        self.assertEqual(len(GeneratedCertificate.objects.all()), 0)
        self._add_course_certificates(count=1, signatory_count=2)
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        response = self.client.get(test_url + '?preview=honor')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

        # mark certificate inactive but accessing in preview mode.
        self._add_course_certificates(count=1,
                                      signatory_count=2,
                                      is_active=False)
        response = self.client.get(test_url + '?preview=honor')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_certificate_configuration(self):
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        response = self.client.get(test_url)
        self.assertIn("Invalid Certificate", response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_evidence_event_emitted(self):
        self.client.logout()
        self._add_course_certificates(count=1, signatory_count=2)
        self.recreate_tracker()
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        actual_event = self.get_event()
        self.assertEqual(actual_event['name'],
                         'edx.certificate.evidence_visited')
        assert_event_matches(
            {
                'user_id': self.user.id,
                'certificate_id': unicode(self.cert.verify_uuid),
                'enrollment_mode': self.cert.mode,
                'certificate_url': test_url,
                'course_id': unicode(self.course.id),
                'social_network': CertificateSocialNetworks.linkedin
            }, actual_event['data'])

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_evidence_event_sent(self):
        cert_url = get_certificate_url(user_id=self.user.id,
                                       course_id=self.course_id)
        test_url = '{}?evidence_visit=1'.format(cert_url)
        self._add_course_certificates(count=1, signatory_count=2)
        self.recreate_tracker()
        assertion = BadgeAssertion(
            user=self.user,
            course_id=self.course_id,
            mode='honor',
            data={
                'image': 'http://www.example.com/image.png',
                'json': {
                    'id': 'http://www.example.com/assertion.json'
                },
                'issuer': 'http://www.example.com/issuer.json',
            })
        assertion.save()
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        assert_event_matches(
            {
                'name': 'edx.badge.assertion.evidence_visited',
                'data': {
                    'course_id': 'testorg/run1/refundable_course',
                    # pylint: disable=no-member
                    'assertion_id': assertion.id,
                    'assertion_json_url':
                    'http://www.example.com/assertion.json',
                    'assertion_image_url': 'http://www.example.com/image.png',
                    'user_id': self.user.id,
                    'issuer': 'http://www.example.com/issuer.json',
                    'enrollment_mode': 'honor',
                },
            },
            self.get_event())

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    def test_request_certificate_without_passing(self):
        self.cert.status = CertificateStatuses.unavailable
        self.cert.save()
        request_certificate_url = reverse(
            'certificates.views.request_certificate')
        response = self.client.post(request_certificate_url,
                                    {'course_id': unicode(self.course.id)})
        self.assertEqual(response.status_code, 200)
        response_json = json.loads(response.content)
        self.assertEqual(CertificateStatuses.notpassing,
                         response_json['add_status'])

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    @override_settings(CERT_QUEUE='test-queue')
    def test_request_certificate_after_passing(self):
        self.cert.status = CertificateStatuses.unavailable
        self.cert.save()
        request_certificate_url = reverse(
            'certificates.views.request_certificate')
        with patch('capa.xqueue_interface.XQueueInterface.send_to_queue'
                   ) as mock_queue:
            mock_queue.return_value = (0, "Successfully queued")
            with patch('courseware.grades.grade') as mock_grade:
                mock_grade.return_value = {'grade': 'Pass', 'percent': 0.75}
                response = self.client.post(
                    request_certificate_url,
                    {'course_id': unicode(self.course.id)})
                self.assertEqual(response.status_code, 200)
                response_json = json.loads(response.content)
                self.assertEqual(CertificateStatuses.generating,
                                 response_json['add_status'])

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    @override_settings(LANGUAGE_CODE='fr')
    def test_certificate_custom_template_with_org_mode_course(self):
        """
        Tests custom template search and rendering.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(1,
                                     mode='honor',
                                     course_key=unicode(self.course.id))
        self._create_custom_template(2, mode='honor')
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))

        with patch(
                'certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{
                    "id": 1,
                    "name": "organization name"
                }],
                [{
                    "id": 2,
                    "name": "organization name 2"
                }],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'lang: fr')
            self.assertContains(
                response, 'course name: {}'.format(self.course.display_name))
            # test with second organization template
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'lang: fr')
            self.assertContains(
                response, 'course name: {}'.format(self.course.display_name))

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_org(self):
        """
        Tests custom template search if if have a single template for all courses of organization.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(1)
        self._create_custom_template(1, mode='honor')
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))

        with patch(
                'certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{
                    "id": 1,
                    "name": "organization name"
                }],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(
                response, 'course name: {}'.format(self.course.display_name))

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_course_mode(self):
        """
        Tests custom template search if if have a single template for a course mode.
        """
        mode = 'honor'
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(mode=mode)
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))

        with patch(
                'certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.return_value = []
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'mode: {}'.format(mode))
Beispiel #34
0
def test_invalid_page_param():
    url = '%s?%s' % (reverse('search'), 'page=a')
    request = RequestFactory().get(url)
    queryset = range(100)
    paginated = paginate(request, queryset)
    eq_(paginated.url, request.build_absolute_uri(request.path) + '?')
Beispiel #35
0
class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
    """
    Tests for the certificates web/html views
    """
    def setUp(self):
        super(CertificatesViewsTests, self).setUp()
        self.client = Client()
        self.course = CourseFactory.create(
            org='testorg', number='run1', display_name='refundable course'
        )
        self.course_id = self.course.location.course_key
        self.user = UserFactory.create(
            email='*****@*****.**',
            username='******',
            password='******'
        )
        self.user.profile.name = "Joe User"
        self.user.profile.save()
        self.client.login(username=self.user.username, password='******')
        self.request = RequestFactory().request()

        self.cert = GeneratedCertificate.objects.create(
            user=self.user,
            course_id=self.course_id,
            verify_uuid=uuid4(),
            download_uuid=uuid4(),
            download_url="http://www.example.com/certificates/download",
            grade="0.95",
            key='the_key',
            distinction=True,
            status='generated',
            mode='honor',
            name=self.user.profile.name,
        )
        CourseEnrollmentFactory.create(
            user=self.user,
            course_id=self.course_id
        )
        CertificateHtmlViewConfigurationFactory.create()
        LinkedInAddToProfileConfigurationFactory.create()

    def _add_course_certificates(self, count=1, signatory_count=0, is_active=True):
        """
        Create certificate for the course.
        """
        signatories = [
            {
                'name': 'Signatory_Name ' + str(i),
                'title': 'Signatory_Title ' + str(i),
                'organization': 'Signatory_Organization ' + str(i),
                'signature_image_path': '/static/certificates/images/demo-sig{}.png'.format(i),
                'id': i,
            } for i in xrange(0, signatory_count)

        ]

        certificates = [
            {
                'id': i,
                'name': 'Name ' + str(i),
                'description': 'Description ' + str(i),
                'course_title': 'course_title_' + str(i),
                'org_logo_path': '/t4x/orgX/testX/asset/org-logo-{}.png'.format(i),
                'signatories': signatories,
                'version': 1,
                'is_active': is_active
            } for i in xrange(0, count)
        ]

        self.course.certificates = {'certificates': certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)

    def _create_custom_template(self, org_id=None, mode=None, course_key=None):
        """
        Creates a custom certificate template entry in DB.
        """
        template_html = """
            <html>
            <body>
                lang: ${LANGUAGE_CODE}
                course name: ${accomplishment_copy_course_name}
                mode: ${course_mode}
                ${accomplishment_copy_course_description}
            </body>
            </html>
        """
        template = CertificateTemplate(
            name='custom template',
            template=template_html,
            organization_id=org_id,
            course_key=course_key,
            mode=mode,
            is_active=True
        )
        template.save()

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_linkedin_share_url(self):
        """
        Test: LinkedIn share URL.
        """
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertTrue(urllib.quote_plus(self.request.build_absolute_uri(test_url)) in response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_rendering_course_organization_data(self):
        """
        Test: organization data should render on certificate web view if course has organization.
        """
        test_organization_data = {
            'name': 'test_organization',
            'description': 'Test Organization Description',
            'active': True,
            'logo': '/logo_test1.png/'
        }
        test_org = organizations_api.add_organization(organization_data=test_organization_data)
        organizations_api.add_organization_course(organization_data=test_org, course_id=unicode(self.course.id))
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn(
            'a course of study offered by test_organization',
            response.content
        )
        self.assertNotIn(
            'a course of study offered by testorg',
            response.content
        )
        self.assertIn(
            '<title>test_organization {} Certificate |'.format(self.course.number, ),
            response.content
        )
        self.assertIn('logo_test1.png', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_valid_certificate(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self._add_course_certificates(count=1, signatory_count=2)
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Hit any "verified" mode-specific branches
        self.cert.mode = 'verified'
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Hit any 'xseries' mode-specific branches
        self.cert.mode = 'xseries'
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_valid_signatories(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self._add_course_certificates(count=1, signatory_count=2)
        response = self.client.get(test_url)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Name 0', response.content)
        self.assertIn('Signatory_Title 0', response.content)
        self.assertIn('Signatory_Organization 0', response.content)
        self.assertIn('/static/certificates/images/demo-sig0.png', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_course_display_name_not_override_with_course_title(self):
        # if certificate in descriptor has not course_title then course name should not be overridden with this title.
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        test_certificates = [
            {
                'id': 0,
                'name': 'Name 0',
                'description': 'Description 0',
                'signatories': [],
                'version': 1,
                'is_active':True
            }
        ]
        self.course.certificates = {'certificates': test_certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)
        response = self.client.get(test_url)
        self.assertNotIn('test_course_title_0', response.content)
        self.assertIn('refundable course', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_view_without_org_logo(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        test_certificates = [
            {
                'id': 0,
                'name': 'Certificate Name 0',
                'signatories': [],
                'version': 1,
                'is_active': True
            }
        ]
        self.course.certificates = {'certificates': test_certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)
        response = self.client.get(test_url)
        # make sure response html has only one organization logo container for edX
        self.assertContains(response, "<li class=\"wrapper-organization\">", 1)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_without_signatories(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course)
        )
        self._add_course_certificates(count=1, signatory_count=0)
        response = self.client.get(test_url)
        self.assertNotIn('Signatory_Name 0', response.content)
        self.assertNotIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    def test_render_html_view_disabled_feature_flag_returns_static_url(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self.assertIn(str(self.cert.download_url), test_url)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_course_id(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id='az/23423/4vs'
        )

        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_course(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id='missing/course/key'
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_user(self):
        test_url = get_certificate_url(
            user_id=111,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_user_certificate(self):
        self.cert.delete()
        self.assertEqual(len(GeneratedCertificate.objects.all()), 0)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_preview_mode(self):
        """
        test certificate web view should render properly along with its signatories information when accessing it in
        preview mode. Either the certificate is marked active or not.
        """
        self.cert.delete()
        self.assertEqual(len(GeneratedCertificate.objects.all()), 0)
        self._add_course_certificates(count=1, signatory_count=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url + '?preview=honor')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

        # mark certificate inactive but accessing in preview mode.
        self._add_course_certificates(count=1, signatory_count=2, is_active=False)
        response = self.client.get(test_url + '?preview=honor')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_certificate_configuration(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn("Invalid Certificate", response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_evidence_event_emitted(self):
        self.client.logout()
        self._add_course_certificates(count=1, signatory_count=2)
        self.recreate_tracker()
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        actual_event = self.get_event()
        self.assertEqual(actual_event['name'], 'edx.certificate.evidence_visited')
        assert_event_matches(
            {
                'user_id': self.user.id,
                'certificate_id': unicode(self.cert.verify_uuid),
                'enrollment_mode': self.cert.mode,
                'certificate_url': test_url,
                'course_id': unicode(self.course.id),
                'social_network': CertificateSocialNetworks.linkedin
            },
            actual_event['data']
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_evidence_event_sent(self):
        cert_url = get_certificate_url(
            user_id=self.user.id,
            course_id=self.course_id
        )
        test_url = '{}?evidence_visit=1'.format(cert_url)
        self._add_course_certificates(count=1, signatory_count=2)
        self.recreate_tracker()
        assertion = BadgeAssertion(
            user=self.user, course_id=self.course_id, mode='honor',
            data={
                'image': 'http://www.example.com/image.png',
                'json': {'id': 'http://www.example.com/assertion.json'},
                'issuer': 'http://www.example.com/issuer.json',

            }
        )
        assertion.save()
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        assert_event_matches(
            {
                'name': 'edx.badge.assertion.evidence_visited',
                'data': {
                    'course_id': 'testorg/run1/refundable_course',
                    # pylint: disable=no-member
                    'assertion_id': assertion.id,
                    'assertion_json_url': 'http://www.example.com/assertion.json',
                    'assertion_image_url': 'http://www.example.com/image.png',
                    'user_id': self.user.id,
                    'issuer': 'http://www.example.com/issuer.json',
                    'enrollment_mode': 'honor',
                },
            },
            self.get_event()
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    def test_request_certificate_without_passing(self):
        self.cert.status = CertificateStatuses.unavailable
        self.cert.save()
        request_certificate_url = reverse('certificates.views.request_certificate')
        response = self.client.post(request_certificate_url, {'course_id': unicode(self.course.id)})
        self.assertEqual(response.status_code, 200)
        response_json = json.loads(response.content)
        self.assertEqual(CertificateStatuses.notpassing, response_json['add_status'])

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    @override_settings(CERT_QUEUE='test-queue')
    def test_request_certificate_after_passing(self):
        self.cert.status = CertificateStatuses.unavailable
        self.cert.save()
        request_certificate_url = reverse('certificates.views.request_certificate')
        with patch('capa.xqueue_interface.XQueueInterface.send_to_queue') as mock_queue:
            mock_queue.return_value = (0, "Successfully queued")
            with patch('courseware.grades.grade') as mock_grade:
                mock_grade.return_value = {'grade': 'Pass', 'percent': 0.75}
                response = self.client.post(request_certificate_url, {'course_id': unicode(self.course.id)})
                self.assertEqual(response.status_code, 200)
                response_json = json.loads(response.content)
                self.assertEqual(CertificateStatuses.generating, response_json['add_status'])

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    @override_settings(LANGUAGE_CODE='fr')
    def test_certificate_custom_template_with_org_mode_course(self):
        """
        Tests custom template search and rendering.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(1, mode='honor', course_key=unicode(self.course.id))
        self._create_custom_template(2, mode='honor')
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 1, "name": "organization name"}],
                [{"id": 2, "name": "organization name 2"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'lang: fr')
            self.assertContains(response, 'course name: {}'.format(self.course.display_name))
            # test with second organization template
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'lang: fr')
            self.assertContains(response, 'course name: {}'.format(self.course.display_name))

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_org(self):
        """
        Tests custom template search if if have a single template for all courses of organization.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(1)
        self._create_custom_template(1, mode='honor')
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 1, "name": "organization name"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'course name: {}'.format(self.course.display_name))

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_course_mode(self):
        """
        Tests custom template search if if have a single template for a course mode.
        """
        mode = 'honor'
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(mode=mode)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.return_value = []
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'mode: {}'.format(mode))
class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
    """
    Tests for the certificates web/html views
    """
    def setUp(self):
        super(CertificatesViewsTests, self).setUp()
        self.client = Client()
        self.course = CourseFactory.create(
            org='testorg', number='run1', display_name='refundable course'
        )
        self.course_id = self.course.location.course_key
        self.user = UserFactory.create(
            email='*****@*****.**',
            username='******',
            password='******'
        )
        self.user.profile.name = "Joe User"
        self.user.profile.save()
        self.client.login(username=self.user.username, password='******')
        self.request = RequestFactory().request()

        self.cert = GeneratedCertificateFactory.create(
            user=self.user,
            course_id=self.course_id,
            download_uuid=uuid4(),
            download_url="http://www.example.com/certificates/download",
            grade="0.95",
            key='the_key',
            distinction=True,
            status='downloadable',
            mode='honor',
            name=self.user.profile.name,
        )
        CourseEnrollmentFactory.create(
            user=self.user,
            course_id=self.course_id
        )
        CertificateHtmlViewConfigurationFactory.create()
        LinkedInAddToProfileConfigurationFactory.create()

    def _add_course_certificates(self, count=1, signatory_count=0, is_active=True):
        """
        Create certificate for the course.
        """
        signatories = [
            {
                'name': 'Signatory_Name ' + str(i),
                'title': 'Signatory_Title ' + str(i),
                'organization': 'Signatory_Organization ' + str(i),
                'signature_image_path': '/static/certificates/images/demo-sig{}.png'.format(i),
                'id': i
            } for i in xrange(signatory_count)

        ]

        certificates = [
            {
                'id': i,
                'name': 'Name ' + str(i),
                'description': 'Description ' + str(i),
                'course_title': 'course_title_' + str(i),
                'org_logo_path': '/t4x/orgX/testX/asset/org-logo-{}.png'.format(i),
                'signatories': signatories,
                'version': 1,
                'is_active': is_active
            } for i in xrange(count)
        ]

        self.course.certificates = {'certificates': certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)

    def _create_custom_template(self, org_id=None, mode=None, course_key=None):
        """
        Creates a custom certificate template entry in DB.
        """
        template_html = """
            <%namespace name='static' file='static_content.html'/>
            <html>
            <body>
                lang: ${LANGUAGE_CODE}
                course name: ${accomplishment_copy_course_name}
                mode: ${course_mode}
                ${accomplishment_copy_course_description}
                ${twitter_url}
                <img class="custom-logo" src="${static.certificate_asset_url('custom-logo')}" />
            </body>
            </html>
        """
        template = CertificateTemplate(
            name='custom template',
            template=template_html,
            organization_id=org_id,
            course_key=course_key,
            mode=mode,
            is_active=True
        )
        template.save()

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_linkedin_share_url(self):
        """
        Test: LinkedIn share URL.
        """
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        test_url = get_certificate_url(course_id=self.course.id, uuid=self.cert.verify_uuid)
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        self.assertIn(urllib.quote_plus(self.request.build_absolute_uri(test_url)), response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    @mock.patch("microsite_configuration.microsite.is_request_in_microsite", _fake_is_request_in_microsite)
    def test_linkedin_share_microsites(self):
        """
        Test: LinkedIn share URL should not be visible when called from within a microsite (for now)
        """
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        test_url = get_certificate_url(course_id=self.cert.course_id, uuid=self.cert.verify_uuid)
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        # the URL should not be present
        self.assertNotIn(urllib.quote_plus(self.request.build_absolute_uri(test_url)), response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_rendering_course_organization_data(self):
        """
        Test: organization data should render on certificate web view if course has organization.
        """
        test_organization_data = {
            'name': 'test organization',
            'short_name': 'test_organization',
            'description': 'Test Organization Description',
            'active': True,
            'logo': '/logo_test1.png/'
        }
        test_org = organizations_api.add_organization(organization_data=test_organization_data)
        organizations_api.add_organization_course(organization_data=test_org, course_id=unicode(self.course.id))
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn(
            'a course of study offered by test_organization, an online learning initiative of test organization',
            response.content
        )
        self.assertNotIn(
            'a course of study offered by testorg',
            response.content
        )
        self.assertIn(
            '<title>test_organization {} Certificate |'.format(self.course.number, ),
            response.content
        )
        self.assertIn('logo_test1.png', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    @patch.dict("django.conf.settings.SOCIAL_SHARING_SETTINGS", {
        "CERTIFICATE_TWITTER": True,
        "CERTIFICATE_FACEBOOK": True,
    })
    @patch.dict("django.conf.settings.MICROSITE_CONFIGURATION", {
        "test_microsite": dict(
            settings.MICROSITE_CONFIGURATION['test_microsite'],
            urls=dict(
                ABOUT=None,
                PRIVACY=None,
                TOS_AND_HONOR=None,
            ),
        )
    })
    @patch.dict("django.conf.settings.MKTG_URL_LINK_MAP", {
        'ABOUT': None,
        'PRIVACY': None,
        'TOS_AND_HONOR': None,
    })
    def test_rendering_maximum_data(self):
        """
        Tests at least one data item from different context update methods to
        make sure every context update method is invoked while rendering certificate template.
        """
        long_org_name = 'Long org name'
        short_org_name = 'short_org_name'
        test_organization_data = {
            'name': long_org_name,
            'short_name': short_org_name,
            'description': 'Test Organization Description',
            'active': True,
            'logo': '/logo_test1.png'
        }
        test_org = organizations_api.add_organization(organization_data=test_organization_data)
        organizations_api.add_organization_course(organization_data=test_org, course_id=unicode(self.course.id))
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        BadgeAssertionFactory.create(
            user=self.user, course_id=self.course_id,
        )
        self.course.cert_html_view_overrides = {
            "logo_src": "/static/certificates/images/course_override_logo.png"
        }

        self.course.save()
        self.store.update_item(self.course, self.user.id)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)

        # Test an item from basic info
        self.assertIn(
            'Terms of Service &amp; Honor Code',
            response.content
        )
        self.assertIn(
            'Certificate ID Number',
            response.content
        )
        # Test an item from html cert configuration
        self.assertIn(
            '<a class="logo" href="http://test_microsite.localhost">',
            response.content
        )
        # Test an item from course info
        self.assertIn(
            'course_title_0',
            response.content
        )
        # Test an item from user info
        self.assertIn(
            "{fullname}, you earned a certificate!".format(fullname=self.user.profile.name),
            response.content
        )
        # Test an item from social info
        self.assertIn(
            "Post on Facebook",
            response.content
        )
        self.assertIn(
            "Share on Twitter",
            response.content
        )
        # Test an item from certificate/org info
        self.assertIn(
            "a course of study offered by {partner_short_name}, "
            "an online learning initiative of "
            "{partner_long_name}.".format(
                partner_short_name=short_org_name,
                partner_long_name=long_org_name,
                platform_name='Test Microsite'
            ),
            response.content
        )
        # Test item from badge info
        self.assertIn(
            "Add to Mozilla Backpack",
            response.content
        )
        # Test item from microsite info
        self.assertIn(
            "http://www.testmicrosite.org/about-us",
            response.content
        )
        # Test course overrides
        self.assertIn(
            "/static/certificates/images/course_override_logo.png",
            response.content
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_valid_certificate(self):
        self._add_course_certificates(count=1, signatory_count=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Hit any "verified" mode-specific branches
        self.cert.mode = 'verified'
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Hit any 'xseries' mode-specific branches
        self.cert.mode = 'xseries'
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_certificate_only_for_downloadable_status(self):
        """
        Tests taht Certificate HTML Web View returns Certificate only if certificate status is 'downloadable',
        for other statuses it should return "Invalid Certificate".
        """
        self._add_course_certificates(count=1, signatory_count=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        # Validate certificate
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # Change status to 'generating' and validate that Certificate Web View returns "Invalid Certificate"
        self.cert.status = CertificateStatuses.generating
        self.cert.save()
        response = self.client.get(test_url)
        self.assertIn("Invalid Certificate", response.content)
        self.assertIn("Cannot Find Certificate", response.content)
        self.assertIn("We cannot find a certificate with this URL or ID number.", response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_html_view_for_invalid_certificate(self):
        """
        Tests that Certificate HTML Web View returns "Cannot Find Certificate" if certificate has been invalidated.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        # Validate certificate
        response = self.client.get(test_url)
        self.assertIn(str(self.cert.verify_uuid), response.content)

        # invalidate certificate and verify that "Cannot Find Certificate" is returned
        self.cert.invalidate()
        response = self.client.get(test_url)
        self.assertIn("Invalid Certificate", response.content)
        self.assertIn("Cannot Find Certificate", response.content)
        self.assertIn("We cannot find a certificate with this URL or ID number.", response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_valid_signatories(self):
        self._add_course_certificates(count=1, signatory_count=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        response = self.client.get(test_url)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Name 0', response.content)
        self.assertIn('Signatory_Title 0', response.content)
        self.assertIn('Signatory_Organization 0', response.content)
        self.assertIn('/static/certificates/images/demo-sig0.png', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_course_display_name_not_override_with_course_title(self):
        # if certificate in descriptor has not course_title then course name should not be overridden with this title.
        test_certificates = [
            {
                'id': 0,
                'name': 'Name 0',
                'description': 'Description 0',
                'signatories': [],
                'version': 1,
                'is_active':True
            }
        ]
        self.course.certificates = {'certificates': test_certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        response = self.client.get(test_url)
        self.assertNotIn('test_course_title_0', response.content)
        self.assertIn('refundable course', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_course_display_overrides(self):
        """
        Tests if `Course Number Display String` or `Course Organization Display` is set for a course
        in advance settings
        Then web certificate should display that course number and course org set in advance
        settings instead of original course number and course org.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        self.course.display_coursenumber = "overridden_number"
        self.course.display_organization = "overridden_org"
        self.store.update_item(self.course, self.user.id)

        response = self.client.get(test_url)
        self.assertIn('overridden_number', response.content)
        self.assertIn('overridden_org', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_view_without_org_logo(self):
        test_certificates = [
            {
                'id': 0,
                'name': 'Certificate Name 0',
                'signatories': [],
                'version': 1,
                'is_active': True
            }
        ]
        self.course.certificates = {'certificates': test_certificates}
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        # make sure response html has only one organization logo container for edX
        self.assertContains(response, "<li class=\"wrapper-organization\">", 1)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_without_signatories(self):
        self._add_course_certificates(count=1, signatory_count=0)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course)
        )
        response = self.client.get(test_url)
        self.assertNotIn('Signatory_Name 0', response.content)
        self.assertNotIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    def test_render_html_view_disabled_feature_flag_returns_static_url(self):
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self.assertIn(str(self.cert.download_url), test_url)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_course(self):
        test_url = "/certificates/user/{user_id}/course/{course_id}".format(
            user_id=self.user.id,
            course_id="missing/course/key"
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_user(self):
        self._add_course_certificates(count=1, signatory_count=0)
        test_url = get_certificate_url(
            user_id=111,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_user_certificate(self):
        self._add_course_certificates(count=1, signatory_count=0)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self.cert.delete()
        self.assertEqual(len(GeneratedCertificate.objects.all()), 0)

        response = self.client.get(test_url)
        self.assertIn('invalid', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED, PLATFORM_NAME=u'Űńíćődé Űńívéŕśítӳ')
    def test_render_html_view_with_unicode_platform_name(self):
        self._add_course_certificates(count=1, signatory_count=0)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_preview_mode(self):
        """
        test certificate web view should render properly along with its signatories information when accessing it in
        preview mode. Either the certificate is marked active or not.
        """
        self.cert.delete()
        self.assertEqual(len(GeneratedCertificate.objects.all()), 0)
        self._add_course_certificates(count=1, signatory_count=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url + '?preview=honor')
        # accessing certificate web view in preview mode without
        # staff or instructor access should show invalid certificate
        self.assertIn('Cannot Find Certificate', response.content)

        CourseStaffRole(self.course.id).add_users(self.user)

        response = self.client.get(test_url + '?preview=honor')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

        # mark certificate inactive but accessing in preview mode.
        self._add_course_certificates(count=1, signatory_count=2, is_active=False)
        response = self.client.get(test_url + '?preview=honor')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_with_preview_mode_when_user_already_has_cert(self):
        """
        test certificate web view should render properly in
        preview mode even if user who is previewing already has a certificate
        generated with different mode.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        CourseStaffRole(self.course.id).add_users(self.user)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        # user has already has certificate generated for 'honor' mode
        # so let's try to preview in 'verified' mode.
        response = self.client.get(test_url + '?preview=verified')
        self.assertNotIn(self.course.display_name, response.content)
        self.assertIn('course_title_0', response.content)
        self.assertIn('Signatory_Title 0', response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_html_view_invalid_certificate_configuration(self):
        self.course.cert_html_view_enabled = True
        self.course.save()
        self.store.update_item(self.course, self.user.id)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertIn("Invalid Certificate", response.content)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_render_500_view_invalid_certificate_configuration(self):
        self._add_course_certificates(count=1, signatory_count=2)
        CertificateHtmlViewConfiguration.objects.all().update(enabled=False)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url + "?preview=honor")
        self.assertIn("Invalid Certificate Configuration", response.content)

        # Verify that Exception is raised when certificate is not in the preview mode
        with self.assertRaises(Exception):
            self.client.get(test_url)

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_evidence_event_emitted(self):
        self.client.logout()
        self._add_course_certificates(count=1, signatory_count=2)
        self.recreate_tracker()
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        actual_event = self.get_event()
        self.assertEqual(actual_event['name'], 'edx.certificate.evidence_visited')
        assert_event_matches(
            {
                'user_id': self.user.id,
                'certificate_id': unicode(self.cert.verify_uuid),
                'enrollment_mode': self.cert.mode,
                'certificate_url': test_url,
                'course_id': unicode(self.course.id),
                'social_network': CertificateSocialNetworks.linkedin
            },
            actual_event['data']
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_evidence_event_sent(self):
        self._add_course_certificates(count=1, signatory_count=2)

        cert_url = get_certificate_url(
            user_id=self.user.id,
            course_id=self.course_id
        )
        test_url = '{}?evidence_visit=1'.format(cert_url)
        self.recreate_tracker()
        assertion = BadgeAssertionFactory.create(
            user=self.user, course_id=self.course_id,
        )
        response = self.client.get(test_url)
        self.assertEqual(response.status_code, 200)
        assert_event_matches(
            {
                'name': 'edx.badge.assertion.evidence_visited',
                'data': {
                    'course_id': 'testorg/run1/refundable_course',
                    'assertion_id': assertion.id,
                    'assertion_json_url': 'http://www.example.com/assertion.json',
                    'assertion_image_url': 'http://www.example.com/image.png',
                    'user_id': self.user.id,
                    'issuer': 'http://www.example.com/issuer.json',
                    'enrollment_mode': 'honor',
                },
            },
            self.get_event()
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    def test_request_certificate_without_passing(self):
        self.cert.status = CertificateStatuses.unavailable
        self.cert.save()
        request_certificate_url = reverse('certificates.views.request_certificate')
        response = self.client.post(request_certificate_url, {'course_id': unicode(self.course.id)})
        self.assertEqual(response.status_code, 200)
        response_json = json.loads(response.content)
        self.assertEqual(CertificateStatuses.notpassing, response_json['add_status'])

    @override_settings(FEATURES=FEATURES_WITH_CERTS_DISABLED)
    @override_settings(CERT_QUEUE='test-queue')
    def test_request_certificate_after_passing(self):
        self.cert.status = CertificateStatuses.unavailable
        self.cert.save()
        request_certificate_url = reverse('certificates.views.request_certificate')
        with patch('capa.xqueue_interface.XQueueInterface.send_to_queue') as mock_queue:
            mock_queue.return_value = (0, "Successfully queued")
            with patch('courseware.grades.grade') as mock_grade:
                mock_grade.return_value = {'grade': 'Pass', 'percent': 0.75}
                response = self.client.post(request_certificate_url, {'course_id': unicode(self.course.id)})
                self.assertEqual(response.status_code, 200)
                response_json = json.loads(response.content)
                self.assertEqual(CertificateStatuses.generating, response_json['add_status'])

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    @override_settings(LANGUAGE_CODE='fr')
    def test_certificate_custom_template_with_org_mode_course(self):
        """
        Tests custom template search and rendering.
        This test should check template matching when org={org}, course={course}, mode={mode}.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(org_id=1, mode='honor', course_key=unicode(self.course.id))
        self._create_custom_template(org_id=2, mode='honor')
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 1, "name": "organization name"}],
                [{"id": 2, "name": "organization name 2"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'lang: fr')
            self.assertContains(response, 'course name: course_title_0')
            # test with second organization template
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'lang: fr')
            self.assertContains(response, 'course name: course_title_0')

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_org(self):
        """
        Tests custom template search if we have a single template for organization and mode
        with course set to Null.
        This test should check template matching when org={org}, course=Null, mode={mode}.
        """
        course = CourseFactory.create(
            org='cstX', number='cst_22', display_name='custom template course'
        )

        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(org_id=1, mode='honor')
        self._create_custom_template(org_id=1, mode='honor', course_key=course.id)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 1, "name": "organization name"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'course name: course_title_0')

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_organization(self):
        """
        Tests custom template search when we have a single template for a organization.
        This test should check template matching when org={org}, course=Null, mode=null.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(org_id=1, mode='honor')
        self._create_custom_template(org_id=1, mode='honor', course_key=self.course.id)
        self._create_custom_template(org_id=2)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.side_effect = [
                [{"id": 2, "name": "organization name 2"}],
            ]
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_custom_template_with_course_mode(self):
        """
        Tests custom template search if we have a single template for a course mode.
        This test should check template matching when org=null, course=Null, mode={mode}.
        """
        mode = 'honor'
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(mode=mode)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.return_value = []
            response = self.client.get(test_url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'mode: {}'.format(mode))

    @ddt.data(True, False)
    def test_certificate_custom_template_with_unicode_data(self, custom_certs_enabled):
        """
        Tests custom template renders properly with unicode data.
        """
        mode = 'honor'
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(mode=mode)
        with patch.dict("django.conf.settings.FEATURES", {
            "CERTIFICATES_HTML_VIEW": True,
            "CUSTOM_CERTIFICATE_TEMPLATES_ENABLED": custom_certs_enabled
        }):
            test_url = get_certificate_url(
                user_id=self.user.id,
                course_id=unicode(self.course.id)
            )
            with patch.dict("django.conf.settings.SOCIAL_SHARING_SETTINGS", {
                "CERTIFICATE_TWITTER": True,
                "CERTIFICATE_TWITTER_TEXT": u"nền tảng học tập"
            }):
                with patch('django.http.HttpRequest.build_absolute_uri') as mock_abs_uri:
                    mock_abs_uri.return_value = '='.join(['http://localhost/?param', u'é'])
                    with patch('certificates.api.get_course_organizations') as mock_get_orgs:
                        mock_get_orgs.return_value = []
                        response = self.client.get(test_url)
                        self.assertEqual(response.status_code, 200)
                        if custom_certs_enabled:
                            self.assertContains(response, 'mode: {}'.format(mode))
                        else:
                            self.assertContains(response, "Tweet this Accomplishment")
                        self.assertContains(response, 'https://twitter.com/intent/tweet')

    @override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
    def test_certificate_asset_by_slug(self):
        """
        Tests certificate template asset display by slug using static.certificate_asset_url method.
        """
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_custom_template(mode='honor')
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )

        # render certificate without template asset
        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.return_value = []
            response = self.client.get(test_url)
            self.assertContains(response, '<img class="custom-logo" src="" />')

        template_asset = CertificateTemplateAsset(
            description='custom logo',
            asset='certificate_template_assets/32/test_logo.png',
            asset_slug='custom-logo',
        )
        template_asset.save()

        # render certificate with template asset
        with patch('certificates.api.get_course_organizations') as mock_get_orgs:
            mock_get_orgs.return_value = []
            response = self.client.get(test_url)
            self.assertContains(
                response, '<img class="custom-logo" src="{}certificate_template_assets/32/test_logo.png" />'.format(
                    settings.MEDIA_URL
                )
            )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    def test_certificate_branding(self):
        """
        Test that link urls in certificate web view are customized according to site branding and
        microsite configuration.
        """
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)

        self.course.save()
        self.store.update_item(self.course, self.user.id)

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
        # logo_image_url Tis present in MICROSITE_CONFIGURATION['test_microsite']["urls"],
        #  so web certificate will use that.
        self.assertContains(
            response,
            settings.MICROSITE_CONFIGURATION['test_microsite']['logo_image_url'],
        )
        # ABOUT is present in MICROSITE_CONFIGURATION['test_microsite']["urls"] so web certificate will use that url.
        self.assertContains(
            response,
            settings.MICROSITE_CONFIGURATION['test_microsite']["urls"]['ABOUT'],
        )
        # PRIVACY is present in MICROSITE_CONFIGURATION['test_microsite']["urls"] so web certificate will use that url.
        self.assertContains(
            response,
            settings.MICROSITE_CONFIGURATION['test_microsite']["urls"]['PRIVACY'],
        )
        # TOS_AND_HONOR is present in MICROSITE_CONFIGURATION['test_microsite']["urls"],
        #  so web certificate will use that url.
        self.assertContains(
            response,
            settings.MICROSITE_CONFIGURATION['test_microsite']["urls"]['TOS_AND_HONOR'],
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    @patch.dict("django.conf.settings.MICROSITE_CONFIGURATION", {
        "test_microsite": dict(
            settings.MICROSITE_CONFIGURATION['test_microsite'],
            urls=dict(
                ABOUT=None,
                PRIVACY=None,
                TOS_AND_HONOR=None,
            ),
        )
    })
    def test_certificate_branding_without_microsite_urls(self):
        """
        Test that links from MKTG_URL_LINK_MAP setting are used if corresponding microsite urls are not present.
        microsite configuration.
        """
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
        self.course.save()
        self.store.update_item(self.course, self.user.id)
        configuration = CertificateHtmlViewConfiguration.get_config()
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
        # ABOUT is not present in MICROSITE_CONFIGURATION['test_microsite']["urls"],
        #  so web certificate will use MKTG_URL_LINK_MAP['ABOUT'] url.
        self.assertContains(
            response,
            settings.MKTG_URL_LINK_MAP['ABOUT'],
        )
        # PRIVACY is not present in MICROSITE_CONFIGURATION['test_microsite']["urls"],
        # so web certificate will use MKTG_URL_LINK_MAP['PRIVACY'] url.
        self.assertContains(
            response,
            settings.MKTG_URL_LINK_MAP['PRIVACY'],
        )
        # TOS_AND_HONOR is not present in MICROSITE_CONFIGURATION['test_microsite']["urls"] or MKTG_URL_LINK_MAP,
        # so web certificate will use CertificateHtmlViewConfiguration url.
        self.assertContains(
            response,
            configuration['microsites']['testmicrosite']['company_tos_url'],
        )

    @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
    @patch.dict("django.conf.settings.MICROSITE_CONFIGURATION", {
        "test_microsite": dict(
            settings.MICROSITE_CONFIGURATION['test_microsite'],
            urls=dict(
                ABOUT=None,
                PRIVACY=None,
                TOS_AND_HONOR=None,
            ),
        )
    })
    @patch.dict("django.conf.settings.MKTG_URL_LINK_MAP", {
        'ABOUT': None,
        'PRIVACY': None,
        'TOS_AND_HONOR': None,
    })
    def test_certificate_without_branding_urls(self):
        """
        Test that links from CertificateHtmlViewConfiguration are used if
        corresponding microsite or marketing urls are not present.
        """
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)

        self.course.save()
        self.store.update_item(self.course, self.user.id)
        configuration = CertificateHtmlViewConfiguration.get_config()

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)

        # ABOUT is not present in MICROSITE_CONFIGURATION['test_microsite']["urls"] or MKTG_URL_LINK_MAP,
        #  so web certificate will use CertificateHtmlViewConfiguration url.
        self.assertContains(
            response,
            configuration['microsites']['testmicrosite']['company_about_url'],
        )
        # PRIVACY is not present in MICROSITE_CONFIGURATION['test_microsite']["urls"] or MKTG_URL_LINK_MAP,
        # so web certificate will use CertificateHtmlViewConfiguration url.
        self.assertContains(
            response,
            configuration['microsites']['testmicrosite']['company_privacy_url'],
        )
        # TOS_AND_HONOR is not present in MICROSITE_CONFIGURATION['test_microsite']["urls"] or MKTG_URL_LINK_MAP,
        # so web certificate will use CertificateHtmlViewConfiguration url.
        self.assertContains(
            response,
            configuration['microsites']['testmicrosite']['company_tos_url'],
        )
Beispiel #37
0
class HydraLinksTestCase(ClearContentTypesTransactionTestCase):
    fixtures = ['projects.json']

    def setUp(self):
        self.user = User.objects.get(email='*****@*****.**')
        self.project = Project.objects.get(slug='emma')
        self.note = Note.objects.create(title='A test note',
                                        project=self.project,
                                        creator=self.user,
                                        last_updater=self.user)

        self.dummy_req = RequestFactory().get('/')

    def test_unauthenticated_hydra_class_request(self):
        """
        An unauthenticated request should only know about a "GET" operation on
        a project item.
        """
        response = self.client.get(reverse(
            'api:notes-detail', args=[self.project.slug, self.note.id]),
                                   HTTP_ACCEPT='application/json')

        self.assertEqual(len(response.data['hydra:operation']), 1)
        self.assertEqual(response.data['hydra:operation'][0]['hydra:method'],
                         'GET')

    def test_authenticated_hydra_class_request(self):
        """
        An authenticated request with sufficient permissions should know about
        "GET", "PUT", and "POST" operations on a project item.
        """
        self.client.login(username='******', password='******')

        response = self.client.get(reverse(
            'api:notes-detail', args=[self.project.slug, self.note.id]),
                                   HTTP_ACCEPT='application/json')

        self.assertEqual(len(response.data['hydra:operation']), 3)
        self.assertEqual(
            [op['hydra:method'] for op in response.data['hydra:operation']],
            ['PUT', 'DELETE', 'GET'])

    def test_authenticated_user_project_home(self):
        """
        The project resource for an authenticated user should show links to
        add items to all projects.
        """
        self.client.login(username='******', password='******')
        response = self.client.get(reverse('api:projects-detail',
                                           args=[self.project.slug]),
                                   HTTP_ACCEPT='application/json')

        embedded = response.data.get('embedded')

        self.assertEqual(
            embedded.keys(),
            map(self.dummy_req.build_absolute_uri, [
                '/projects/emma/vocab/#Project/notes',
                '/projects/emma/vocab/#Project/topics',
                '/projects/emma/vocab/#Project/documents',
            ]))

        # FIXME: Should be able to update projects' info in the API
        # self.assertEqual(len(response.data.get('hydra:operation')), 3)
        self.assertEqual(len(response.data.get('hydra:operation')), 1)

        link_class_embeds = [
            hydra_class for hydra_class in embedded.values()
            if hydra_class['@type'] == 'hydra:Link'
        ]

        self.assertEqual(len(link_class_embeds), 3)

        project_url = self.dummy_req.build_absolute_uri(
            self.project.get_absolute_url())
        project_url += 'vocab/#'

        self.assertEqual([
            link_class['hydra:supportedOperation'][0]
            for link_class in link_class_embeds
        ], [
            create_operation(item_type, project_url)
            for item_type in ('Note', 'Topic', 'Document')
        ])

        self.assertEqual(
            response.data['@context']['notes'], {
                '@id':
                self.dummy_req.build_absolute_uri(
                    '/projects/emma/vocab/#Project/notes'),
                '@type':
                '@id'
            })

    def test_authenticated_user_home(self):
        self.client.login(username='******', password='******')
        response = self.client.get('/', HTTP_ACCEPT='application/json')

        project_url = self.dummy_req.build_absolute_uri(
            self.project.get_absolute_url())

        self.assertEqual(
            response.data.get('affiliated_projects').keys(), [project_url])
        self.assertEqual(
            len(response.data['affiliated_projects'].values()[0]['@context']),
            3)
        self.assertEqual(len(response.data.get('embedded')), 3)