Esempio n. 1
0
    def test_get_many(self, mock_warning, mock_info):
        pathways = PathwayFactory.create_batch(3)

        # Cache details for 2 of 3 programs.
        partial_pathways = {
            PATHWAY_CACHE_KEY_TPL.format(id=pathway['id']): pathway
            for pathway in pathways[:2]
        }
        cache.set_many(partial_pathways, None)

        # When called before pathways are cached, the function should return an
        # empty list and log a warning.
        assert get_pathways(self.site) == []
        mock_warning.assert_called_once_with(
            'Failed to get credit pathway ids from the cache.')
        mock_warning.reset_mock()

        # Cache all 3 pathways
        cache.set(
            SITE_PATHWAY_IDS_CACHE_KEY_TPL.format(domain=self.site.domain),
            [pathway['id'] for pathway in pathways], None)

        actual_pathways = get_pathways(self.site)

        # The 2 cached pathways should be returned while info and warning
        # messages should be logged for the missing one.
        assert {pathway['id'] for pathway in actual_pathways} ==\
               {pathway['id'] for pathway in partial_pathways.values()}
        mock_info.assert_called_with(
            'Failed to get details for 1 pathways. Retrying.')
        mock_warning.assert_called_with(
            'Failed to get details for credit pathway {id} from the cache.'.
            format(id=pathways[2]['id']))
        mock_warning.reset_mock()

        # We can't use a set comparison here because these values are dictionaries
        # and aren't hashable. We've already verified that all pathways came out
        # of the cache above, so all we need to do here is verify the accuracy of
        # the data itself.
        for pathway in actual_pathways:
            key = PATHWAY_CACHE_KEY_TPL.format(id=pathway['id'])
            assert pathway == partial_pathways[key]

        # Cache details for all 3 pathways.
        all_pathways = {
            PATHWAY_CACHE_KEY_TPL.format(id=pathway['id']): pathway
            for pathway in pathways
        }
        cache.set_many(all_pathways, None)

        actual_pathways = get_pathways(self.site)

        # All 3 pathways should be returned.
        assert {pathway['id'] for pathway in actual_pathways} ==\
               {pathway['id'] for pathway in all_pathways.values()}
        assert not mock_warning.called

        for pathway in actual_pathways:
            key = PATHWAY_CACHE_KEY_TPL.format(id=pathway['id'])
            assert pathway == all_pathways[key]
Esempio n. 2
0
    def test_get_one(self, mock_warning, _mock_info):
        expected_pathway = PathwayFactory()
        expected_id = expected_pathway['id']

        self.assertEqual(get_pathways(self.site, pathway_id=expected_id), None)
        mock_warning.assert_called_once_with(
            u'Failed to get details for credit pathway {id} from the cache.'.
            format(id=expected_id))
        mock_warning.reset_mock()

        cache.set(PATHWAY_CACHE_KEY_TPL.format(id=expected_id),
                  expected_pathway, None)

        actual_pathway = get_pathways(self.site, pathway_id=expected_id)
        self.assertEqual(actual_pathway, expected_pathway)
        self.assertFalse(mock_warning.called)
Esempio n. 3
0
    def test_get_many_with_missing(self, mock_cache, mock_warning, mock_info):
        pathways = PathwayFactory.create_batch(3)

        all_pathways = {
            PATHWAY_CACHE_KEY_TPL.format(id=pathway['id']): pathway for pathway in pathways
        }

        partial_pathways = {
            PATHWAY_CACHE_KEY_TPL.format(id=pathway['id']): pathway for pathway in pathways[:2]
        }

        def fake_get_many(keys):
            if len(keys) == 1:
                return {PATHWAY_CACHE_KEY_TPL.format(id=pathways[-1]['id']): pathways[-1]}
            else:
                return partial_pathways

        mock_cache.get.return_value = [pathway['id'] for pathway in pathways]
        mock_cache.get_many.side_effect = fake_get_many

        actual_pathways = get_pathways(self.site)

        # All 3 cached pathways should be returned. An info message should be
        # logged about the one that was initially missing, but the code should
        # be able to stitch together all the details.
        self.assertEqual(
            set(pathway['id'] for pathway in actual_pathways),
            set(pathway['id'] for pathway in all_pathways.values())
        )
        self.assertFalse(mock_warning.called)
        mock_info.assert_called_with('Failed to get details for 1 pathways. Retrying.')

        for pathway in actual_pathways:
            key = PATHWAY_CACHE_KEY_TPL.format(id=pathway['id'])
            self.assertEqual(pathway, all_pathways[key])
Esempio n. 4
0
    def test_get_one(self, mock_warning, _mock_info):
        expected_pathway = PathwayFactory()
        expected_id = expected_pathway['id']

        assert get_pathways(self.site, pathway_id=expected_id) is None
        mock_warning.assert_called_once_with(
            f'Failed to get details for credit pathway {expected_id} from the cache.'
        )
        mock_warning.reset_mock()

        cache.set(PATHWAY_CACHE_KEY_TPL.format(id=expected_id),
                  expected_pathway, None)

        actual_pathway = get_pathways(self.site, pathway_id=expected_id)
        assert actual_pathway == expected_pathway
        assert not mock_warning.called
Esempio n. 5
0
    def test_get_one(self, mock_warning, _mock_info):
        expected_pathway = PathwayFactory()
        expected_id = expected_pathway['id']

        self.assertEqual(get_pathways(self.site, pathway_id=expected_id), None)
        mock_warning.assert_called_once_with(
            'Failed to get details for credit pathway {id} from the cache.'.format(id=expected_id)
        )
        mock_warning.reset_mock()

        cache.set(
            PATHWAY_CACHE_KEY_TPL.format(id=expected_id),
            expected_pathway,
            None
        )

        actual_pathway = get_pathways(self.site, pathway_id=expected_id)
        self.assertEqual(actual_pathway, expected_pathway)
        self.assertFalse(mock_warning.called)
Esempio n. 6
0
def get_industry_and_credit_pathways(program_data, site):
    """Returns pathways of a program."""
    industry_pathways = []
    credit_pathways = []
    try:
        for pathway_id in program_data['pathway_ids']:
            pathway = get_pathways(site, pathway_id)
            if pathway and pathway['email']:
                if pathway['pathway_type'] == PathwayType.CREDIT.value:
                    credit_pathways.append(pathway)
                elif pathway['pathway_type'] == PathwayType.INDUSTRY.value:
                    industry_pathways.append(pathway)
    # if pathway caching did not complete fully (no pathway_ids)
    except KeyError:
        pass

    return industry_pathways, credit_pathways
Esempio n. 7
0
    def render_to_fragment(self, request, program_uuid, **kwargs):
        """View details about a specific program."""
        programs_config = kwargs.get(
            'programs_config') or ProgramsApiConfig.current()
        if not programs_config.enabled or not request.user.is_authenticated:
            raise Http404

        meter = ProgramProgressMeter(request.site,
                                     request.user,
                                     uuid=program_uuid)
        program_data = meter.programs[0]

        if not program_data:
            raise Http404

        try:
            mobile_only = json.loads(request.GET.get('mobile_only', 'false'))
        except ValueError:
            mobile_only = False

        program_data = ProgramDataExtender(program_data,
                                           request.user,
                                           mobile_only=mobile_only).extend()
        course_data = meter.progress(programs=[program_data],
                                     count_only=False)[0]
        certificate_data = get_certificates(request.user, program_data)

        program_data.pop('courses')
        skus = program_data.get('skus')
        ecommerce_service = EcommerceService()

        # TODO: Don't have business logic of course-certificate==record-available here in LMS.
        # Eventually, the UI should ask Credentials if there is a record available and get a URL from it.
        # But this is here for now so that we can gate this URL behind both this business logic and
        # a waffle flag. This feature is in active developoment.
        program_record_url = get_credentials_records_url(
            program_uuid=program_uuid)
        if not certificate_data:
            program_record_url = None

        industry_pathways = []
        credit_pathways = []
        try:
            for pathway_id in program_data['pathway_ids']:
                pathway = get_pathways(request.site, pathway_id)
                if pathway and pathway['email']:
                    if pathway['pathway_type'] == PathwayType.CREDIT.value:
                        credit_pathways.append(pathway)
                    elif pathway['pathway_type'] == PathwayType.INDUSTRY.value:
                        industry_pathways.append(pathway)
        # if pathway caching did not complete fully (no pathway_ids)
        except KeyError:
            pass

        urls = {
            'program_listing_url':
            reverse('program_listing_view'),
            'track_selection_url':
            strip_course_id(
                reverse('course_modes_choose',
                        kwargs={'course_id': FAKE_COURSE_KEY})),
            'commerce_api_url':
            reverse('commerce_api:v0:baskets:create'),
            'buy_button_url':
            ecommerce_service.get_checkout_page_url(*skus),
            'program_record_url':
            program_record_url,
        }

        context = {
            'urls': urls,
            'user_preferences': get_user_preferences(request.user),
            'program_data': program_data,
            'course_data': course_data,
            'certificate_data': certificate_data,
            'industry_pathways': industry_pathways,
            'credit_pathways': credit_pathways,
        }

        html = render_to_string(
            'learner_dashboard/program_details_fragment.html', context)
        program_details_fragment = Fragment(html)
        self.add_fragment_resource_urls(program_details_fragment)
        return program_details_fragment
Esempio n. 8
0
    def test_get_many(self, mock_warning, mock_info):
        pathways = PathwayFactory.create_batch(3)

        # Cache details for 2 of 3 programs.
        partial_pathways = {
            PATHWAY_CACHE_KEY_TPL.format(id=pathway['id']): pathway for pathway in pathways[:2]
        }
        cache.set_many(partial_pathways, None)

        # When called before pathways are cached, the function should return an
        # empty list and log a warning.
        self.assertEqual(get_pathways(self.site), [])
        mock_warning.assert_called_once_with('Failed to get credit pathway ids from the cache.')
        mock_warning.reset_mock()

        # Cache all 3 pathways
        cache.set(
            SITE_PATHWAY_IDS_CACHE_KEY_TPL.format(domain=self.site.domain),
            [pathway['id'] for pathway in pathways],
            None
        )

        actual_pathways = get_pathways(self.site)

        # The 2 cached pathways should be returned while info and warning
        # messages should be logged for the missing one.
        self.assertEqual(
            set(pathway['id'] for pathway in actual_pathways),
            set(pathway['id'] for pathway in partial_pathways.values())
        )
        mock_info.assert_called_with('Failed to get details for 1 pathways. Retrying.')
        mock_warning.assert_called_with(
            'Failed to get details for credit pathway {id} from the cache.'.format(id=pathways[2]['id'])
        )
        mock_warning.reset_mock()

        # We can't use a set comparison here because these values are dictionaries
        # and aren't hashable. We've already verified that all pathways came out
        # of the cache above, so all we need to do here is verify the accuracy of
        # the data itself.
        for pathway in actual_pathways:
            key = PATHWAY_CACHE_KEY_TPL.format(id=pathway['id'])
            self.assertEqual(pathway, partial_pathways[key])

        # Cache details for all 3 pathways.
        all_pathways = {
            PATHWAY_CACHE_KEY_TPL.format(id=pathway['id']): pathway for pathway in pathways
        }
        cache.set_many(all_pathways, None)

        actual_pathways = get_pathways(self.site)

        # All 3 pathways should be returned.
        self.assertEqual(
            set(pathway['id'] for pathway in actual_pathways),
            set(pathway['id'] for pathway in all_pathways.values())
        )
        self.assertFalse(mock_warning.called)

        for pathway in actual_pathways:
            key = PATHWAY_CACHE_KEY_TPL.format(id=pathway['id'])
            self.assertEqual(pathway, all_pathways[key])
Esempio n. 9
0
    def render_to_fragment(self, request, program_uuid, **kwargs):
        """View details about a specific program."""
        programs_config = kwargs.get('programs_config') or ProgramsApiConfig.current()
        if not programs_config.enabled or not request.user.is_authenticated:
            raise Http404

        meter = ProgramProgressMeter(request.site, request.user, uuid=program_uuid)
        program_data = meter.programs[0]

        if not program_data:
            raise Http404

        try:
            mobile_only = json.loads(request.GET.get('mobile_only', 'false'))
        except ValueError:
            mobile_only = False

        program_data = ProgramDataExtender(program_data, request.user, mobile_only=mobile_only).extend()
        course_data = meter.progress(programs=[program_data], count_only=False)[0]
        certificate_data = get_certificates(request.user, program_data)

        program_data.pop('courses')
        skus = program_data.get('skus')
        ecommerce_service = EcommerceService()

        # TODO: Don't have business logic of course-certificate==record-available here in LMS.
        # Eventually, the UI should ask Credentials if there is a record available and get a URL from it.
        # But this is here for now so that we can gate this URL behind both this business logic and
        # a waffle flag. This feature is in active developoment.
        program_record_url = get_credentials_records_url(program_uuid=program_uuid)
        if not certificate_data:
            program_record_url = None

        pathways = []
        try:
            for pathway_id in program_data['pathway_ids']:
                pathway = get_pathways(request.site, pathway_id)
                if pathway and pathway['email']:
                    pathways.append(pathway)
        # if pathway caching did not complete fully (no pathway_ids)
        except KeyError:
            pass

        urls = {
            'program_listing_url': reverse('program_listing_view'),
            'track_selection_url': strip_course_id(
                reverse('course_modes_choose', kwargs={'course_id': FAKE_COURSE_KEY})
            ),
            'commerce_api_url': reverse('commerce_api:v0:baskets:create'),
            'buy_button_url': ecommerce_service.get_checkout_page_url(*skus),
            'program_record_url': program_record_url,
        }

        context = {
            'urls': urls,
            'user_preferences': get_user_preferences(request.user),
            'program_data': program_data,
            'course_data': course_data,
            'certificate_data': certificate_data,
            'pathways': pathways,
        }

        html = render_to_string('learner_dashboard/program_details_fragment.html', context)
        program_details_fragment = Fragment(html)
        self.add_fragment_resource_urls(program_details_fragment)
        return program_details_fragment