Пример #1
0
def view_programs(request):
    """View programs in which the user is engaged."""
    show_program_listing = ProgramsApiConfig.current().show_program_listing
    if not show_program_listing:
        raise Http404

    meter = utils.ProgramProgressMeter(request.user)
    programs = meter.engaged_programs

    # TODO: Pull 'xseries' string from configuration model.
    marketing_root = urljoin(settings.MKTG_URLS.get('ROOT'), 'xseries').strip('/')
    for program in programs:
        program['display_category'] = utils.get_display_category(program)
        program['marketing_url'] = '{root}/{slug}'.format(
            root=marketing_root,
            slug=program['marketing_slug']
        )

    context = {
        'programs': programs,
        'progress': meter.progress,
        'xseries_url': marketing_root if ProgramsApiConfig.current().show_xseries_ad else None,
        'nav_hidden': True,
        'show_program_listing': show_program_listing,
        'credentials': get_programs_credentials(request.user, category='xseries'),
        'disable_courseware_js': True,
        'uses_pattern_library': True
    }

    return render_to_response('learner_dashboard/programs.html', context)
Пример #2
0
def program_details(request, program_id):
    """View details about a specific program."""
    show_program_details = ProgramsApiConfig.current().show_program_details
    if not show_program_details:
        raise Http404

    program_data = utils.get_programs(request.user, program_id=program_id)

    if not program_data:
        raise Http404

    program_data = utils.supplement_program_data(program_data, request.user)
    show_program_listing = ProgramsApiConfig.current().show_program_listing

    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')
    }

    context = {
        'program_data': program_data,
        'urls': urls,
        'show_program_listing': show_program_listing,
        'nav_hidden': True,
        'disable_courseware_js': True,
        'uses_pattern_library': True
    }

    return render_to_response('learner_dashboard/program_details.html', context)
Пример #3
0
def view_programs(request):
    """View programs in which the user is engaged."""
    show_program_listing = ProgramsApiConfig.current().show_program_listing
    if not show_program_listing:
        raise Http404

    enrollments = list(get_course_enrollments(request.user, None, []))
    meter = ProgramProgressMeter(request.user, enrollments)
    programs = meter.engaged_programs

    # TODO: Pull 'xseries' string from configuration model.
    marketing_root = urljoin(settings.MKTG_URLS.get('ROOT'), 'xseries').strip('/')
    for program in programs:
        program['display_category'] = get_display_category(program)
        program['marketing_url'] = '{root}/{slug}'.format(
            root=marketing_root,
            slug=program['marketing_slug']
        )

    return render_to_response('learner_dashboard/programs.html', {
        'programs': programs,
        'progress': meter.progress,
        'xseries_url': marketing_root if ProgramsApiConfig.current().show_xseries_ad else None,
        'nav_hidden': True,
        'show_program_listing': show_program_listing,
        'credentials': _get_xseries_credentials(request.user)
    })
Пример #4
0
    def test_is_cache_enabled_returns_false(self, enabled, cache_ttl, _mock_cache):
        """Verify that the method 'is_cache_enabled' returns false if
        'cache_ttl' value is 0 or config is not enabled.
        """
        self.assertFalse(ProgramsApiConfig.current().is_cache_enabled)

        self.create_config(enabled=enabled, cache_ttl=cache_ttl)
        self.assertFalse(ProgramsApiConfig.current().is_cache_enabled)
Пример #5
0
def get_programs_for_dashboard(user, course_keys):
    """Build a dictionary of programs, keyed by course.

    Given a user and an iterable of course keys, find all the programs relevant
    to the user's dashboard and return them in a dictionary keyed by course key.

    Arguments:
        user (User): The user to authenticate as when requesting programs.
        course_keys (list): List of course keys representing the courses in which
            the given user has active enrollments.

    Returns:
        dict, containing programs keyed by course. Empty if programs cannot be retrieved.
    """
    programs_config = ProgramsApiConfig.current()
    course_programs = {}

    if not programs_config.is_student_dashboard_enabled:
        log.debug('Display of programs on the student dashboard is disabled.')
        return course_programs

    programs = get_programs(user)
    if not programs:
        log.debug('No programs found for the user with ID %d.', user.id)
        return course_programs

    course_ids = [unicode(c) for c in course_keys]
    course_programs = flatten_programs(programs, course_ids)

    return course_programs
Пример #6
0
def attach_program_detail_url(programs):
    """Extend program representations by attaching a URL to be used when linking to program details.

    Facilitates the building of context to be passed to templates containing program data.

    Arguments:
        programs (list): Containing dicts representing programs.

    Returns:
        list, containing extended program dicts
    """
    programs_config = ProgramsApiConfig.current()
    marketing_url = get_program_marketing_url(programs_config)

    for program in programs:
        if programs_config.show_program_details:
            base = reverse('program_details_view', kwargs={'program_id': program['id']}).rstrip('/')
            slug = slugify(program['name'])
        else:
            # TODO: Remove. Learners should always be sent to the LMS' program details page.
            base = marketing_url
            slug = program['marketing_slug']

        program['detail_url'] = '{base}/{slug}'.format(base=base, slug=slug)

    return programs
Пример #7
0
def program_listing(request):
    """View a list of programs in which the user is engaged."""
    programs_config = ProgramsApiConfig.current()
    if not programs_config.show_program_listing:
        raise Http404

    meter = utils.ProgramProgressMeter(request.user)
    programs = meter.engaged_programs

    marketing_url = urljoin(settings.MKTG_URLS.get('ROOT'), programs_config.marketing_path).rstrip('/')

    for program in programs:
        program['detail_url'] = utils.get_program_detail_url(program, marketing_url)

    context = {
        'credentials': get_programs_credentials(request.user),
        'disable_courseware_js': True,
        'marketing_url': marketing_url,
        'nav_hidden': True,
        'programs': programs,
        'progress': meter.progress,
        'show_program_listing': programs_config.show_program_listing,
        'uses_pattern_library': True,
    }

    return render_to_response('learner_dashboard/programs.html', context)
Пример #8
0
    def test_get_paginated_data(self):
        """Verify that paginated data can be retrieved."""
        program_config = self.create_programs_config()

        expected_collection = ['some', 'test', 'data']
        url = ProgramsApiConfig.current().internal_api_url.strip('/') + '/programs/?page={}'

        responses = []
        for page, record in enumerate(expected_collection, start=1):
            data = {
                'next': url.format(page + 1) if page < len(expected_collection) else None,
                'results': [record],
            }

            body = json.dumps(data)
            responses.append(
                httpretty.Response(body=body, content_type='application/json')
            )

        self._mock_programs_api(responses)

        actual_collection = get_edx_api_data(program_config, self.user, 'programs')
        self.assertEqual(actual_collection, expected_collection)

        self._assert_num_requests(len(expected_collection))
Пример #9
0
    def _mock_programs_api(self, responses, url=None):
        """Helper for mocking out Programs API URLs."""
        self.assertTrue(httpretty.is_enabled(), msg='httpretty must be enabled to mock Programs API calls.')

        url = url if url else ProgramsApiConfig.current().internal_api_url.strip('/') + '/programs/'

        httpretty.register_uri(httpretty.GET, url, responses=responses)
Пример #10
0
def program_details(request, program_id):
    """View details about a specific program."""
    programs_config = ProgramsApiConfig.current()
    if not programs_config.show_program_details:
        raise Http404

    program_data = utils.get_programs(request.user, program_id=program_id)

    if not program_data:
        raise Http404

    program_data = utils.ProgramDataExtender(program_data, request.user).extend()

    urls = {
        'program_listing_url': reverse('program_listing_view'),
        'track_selection_url': '',
        'commerce_api_url': reverse('commerce_api:v0:baskets:create'),
    }

    context = {
        'program_data': program_data,
        'urls': urls,
        'show_program_listing': programs_config.show_program_listing,
        'nav_hidden': True,
        'disable_courseware_js': True,
        'uses_pattern_library': False
    }

    return render_to_response('learner_dashboard/program_details.html', context)
Пример #11
0
def program_details(request, program_uuid):
    """View details about a specific program."""
    programs_config = ProgramsApiConfig.current()
    if not programs_config.enabled:
        raise Http404

    program_data = get_programs(uuid=program_uuid)
    if not program_data:
        raise Http404

    program_data = ProgramDataExtender(program_data, request.user).extend()

    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'),
    }

    context = {
        'program_data': program_data,
        'urls': urls,
        'show_program_listing': programs_config.enabled,
        'nav_hidden': True,
        'disable_courseware_js': True,
        'uses_pattern_library': True,
        'user_preferences': get_user_preferences(request.user)
    }

    return render_to_response('learner_dashboard/program_details.html', context)
Пример #12
0
    def render_to_fragment(self, request, **kwargs):
        """
        Render the program listing fragment.
        """
        user = request.user
        try:
            mobile_only = json.loads(request.GET.get('mobile_only', 'false'))
        except ValueError:
            mobile_only = False

        programs_config = kwargs.get('programs_config') or ProgramsApiConfig.current()
        if not programs_config.enabled or not user.is_authenticated:
            raise Http404

        meter = ProgramProgressMeter(request.site, user, mobile_only=mobile_only)

        context = {
            'marketing_url': get_program_marketing_url(programs_config),
            'programs': meter.engaged_programs,
            'progress': meter.progress()
        }
        html = render_to_string('learner_dashboard/programs_fragment.html', context)
        programs_fragment = Fragment(html)
        self.add_fragment_resource_urls(programs_fragment)

        return programs_fragment
Пример #13
0
def program_details(request, program_id):
    """View details about a specific program."""
    programs_config = ProgramsApiConfig.current()
    if not programs_config.show_program_details:
        raise Http404

    program_data = utils.get_programs(request.user, program_id=program_id)

    if not program_data:
        raise Http404

    program_data = utils.supplement_program_data(program_data, request.user)

    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"),
    }

    context = {
        "program_data": program_data,
        "urls": urls,
        "show_program_listing": programs_config.show_program_listing,
        "nav_hidden": True,
        "disable_courseware_js": True,
        "uses_pattern_library": True,
    }

    return render_to_response("learner_dashboard/program_details.html", context)
Пример #14
0
def view_programs(request):
    """View programs in which the user is engaged."""
    programs_config = ProgramsApiConfig.current()
    if not programs_config.show_program_listing:
        raise Http404

    meter = utils.ProgramProgressMeter(request.user)
    programs = meter.engaged_programs

    # TODO: Pull 'xseries' string from configuration model.
    marketing_root = urljoin(settings.MKTG_URLS.get("ROOT"), "xseries").rstrip("/")

    for program in programs:
        program["detail_url"] = utils.get_program_detail_url(program, marketing_root)
        program["display_category"] = utils.get_display_category(program)

    context = {
        "programs": programs,
        "progress": meter.progress,
        "xseries_url": marketing_root if programs_config.show_xseries_ad else None,
        "nav_hidden": True,
        "show_program_listing": programs_config.show_program_listing,
        "credentials": get_programs_credentials(request.user, category="xseries"),
        "disable_courseware_js": True,
        "uses_pattern_library": True,
    }

    return render_to_response("learner_dashboard/programs.html", context)
Пример #15
0
def get_programs(user, program_id=None):
    """Given a user, get programs from the Programs service.

    Returned value is cached depending on user permissions. Staff users making requests
    against Programs will receive unpublished programs, while regular users will only receive
    published programs.

    Arguments:
        user (User): The user to authenticate as when requesting programs.

    Keyword Arguments:
        program_id (int): Identifies a specific program for which to retrieve data.

    Returns:
        list of dict, representing programs returned by the Programs service.
        dict, if a specific program is requested.
    """
    programs_config = ProgramsApiConfig.current()

    # Bypass caching for staff users, who may be creating Programs and want
    # to see them displayed immediately.
    cache_key = programs_config.CACHE_KEY if programs_config.is_cache_enabled and not user.is_staff else None

    programs = get_edx_api_data(programs_config, user, 'programs', resource_id=program_id, cache_key=cache_key)

    # Mix in munged MicroMasters data from the catalog.
    if not program_id:
        programs += [
            munge_catalog_program(micromaster) for micromaster in get_catalog_programs(user, type='MicroMasters')
        ]

    return programs
Пример #16
0
 def get(self, request, *args, **kwargs):
     """Generate and return a token, if the integration is enabled."""
     if ProgramsApiConfig.current().is_studio_tab_enabled:
         id_token = get_id_token(request.user, 'programs')
         return JsonResponse({'id_token': id_token})
     else:
         raise Http404
Пример #17
0
def get_programs(user, program_id=None):
    """Given a user, get programs from the Programs service.
    Returned value is cached depending on user permissions. Staff users making requests
    against Programs will receive unpublished programs, while regular users will only receive
    published programs.

    Arguments:
        user (User): The user to authenticate as when requesting programs.

    Keyword Arguments:
        program_id (int): Identifies a specific program for which to retrieve data.

    Returns:
        list of dict, representing programs returned by the Programs service.
    """
    programs_config = ProgramsApiConfig.current()

    # Bypass caching for staff users, who may be creating Programs and want
    # to see them displayed immediately.
    cache_key = programs_config.CACHE_KEY if programs_config.is_cache_enabled and not user.is_staff else None

    data = get_edx_api_data(programs_config, user, 'programs', resource_id=program_id, cache_key=cache_key)

    # TODO: Temporary, to be removed once category names are cased for display. ECOM-5018.
    if data and program_id:
        data['category'] = data['category'].lower()
    else:
        for program in data:
            program['category'] = program['category'].lower()

    return data
Пример #18
0
    def mock_programs_api(self, data):
        """Helper for mocking out Programs API URLs."""
        self.assertTrue(httpretty.is_enabled(), msg='httpretty must be enabled to mock Programs API calls.')

        url = ProgramsApiConfig.current().internal_api_url.strip('/') + '/programs/'
        body = json.dumps({'results': data})

        httpretty.register_uri(httpretty.GET, url, body=body, content_type='application/json')
Пример #19
0
 def test_api_urls(self, _mock_cache):
     """
     Ensure the api url methods return correct concatenations of service
     URLs and version numbers.
     """
     self.create_config()
     api_config = ProgramsApiConfig.current()
     self.assertEqual(api_config.internal_api_url, "{}api/v1/".format(self.INTERNAL_URL))
     self.assertEqual(api_config.public_api_url, "{}api/v1/".format(self.PUBLIC_URL))
Пример #20
0
    def test_cache_utilization(self):
        """Verify that when enabled, the cache is used."""
        program_config = self.create_programs_config(cache_ttl=5)

        expected_collection = ['some', 'test', 'data']
        data = {
            'next': None,
            'results': expected_collection,
        }

        self._mock_programs_api(
            [httpretty.Response(body=json.dumps(data), content_type='application/json')],
        )

        resource_id = 1
        url = '{api_root}/programs/{resource_id}/'.format(
            api_root=ProgramsApiConfig.current().internal_api_url.strip('/'),
            resource_id=resource_id,
        )

        expected_resource = {'key': 'value'}

        self._mock_programs_api(
            [httpretty.Response(body=json.dumps(expected_resource), content_type='application/json')],
            url=url
        )

        cache_key = ProgramsApiConfig.current().CACHE_KEY

        # Warm up the cache.
        get_edx_api_data(program_config, self.user, 'programs', cache_key=cache_key)
        get_edx_api_data(program_config, self.user, 'programs', resource_id=resource_id, cache_key=cache_key)

        # Hit the cache.
        actual_collection = get_edx_api_data(program_config, self.user, 'programs', cache_key=cache_key)
        self.assertEqual(actual_collection, expected_collection)

        actual_resource = get_edx_api_data(
            program_config, self.user, 'programs', resource_id=resource_id, cache_key=cache_key
        )
        self.assertEqual(actual_resource, expected_resource)

        # Verify that only two requests were made, not four.
        self._assert_num_requests(2)
Пример #21
0
def learner_profile_context(request, profile_username, user_is_staff):
    """Context for the learner profile page.

    Args:
        logged_in_user (object): Logged In user.
        profile_username (str): username of user whose profile is requested.
        user_is_staff (bool): Logged In user has staff access.
        build_absolute_uri_func ():

    Returns:
        dict

    Raises:
        ObjectDoesNotExist: the specified profile_username does not exist.
    """
    profile_user = User.objects.get(username=profile_username)
    logged_in_user = request.user

    own_profile = (logged_in_user.username == profile_username)

    account_settings_data = get_account_settings(request, profile_username)

    preferences_data = get_user_preferences(profile_user, profile_username)

    context = {
        'data': {
            'profile_user_id': profile_user.id,
            'default_public_account_fields': settings.ACCOUNT_VISIBILITY_CONFIGURATION['public_fields'],
            'default_visibility': settings.ACCOUNT_VISIBILITY_CONFIGURATION['default_visibility'],
            'accounts_api_url': reverse("accounts_api", kwargs={'username': profile_username}),
            'preferences_api_url': reverse('preferences_api', kwargs={'username': profile_username}),
            'preferences_data': preferences_data,
            'account_settings_data': account_settings_data,
            'profile_image_upload_url': reverse('profile_image_upload', kwargs={'username': profile_username}),
            'profile_image_remove_url': reverse('profile_image_remove', kwargs={'username': profile_username}),
            'profile_image_max_bytes': settings.PROFILE_IMAGE_MAX_BYTES,
            'profile_image_min_bytes': settings.PROFILE_IMAGE_MIN_BYTES,
            'account_settings_page_url': reverse('account_settings'),
            'has_preferences_access': (logged_in_user.username == profile_username or user_is_staff),
            'own_profile': own_profile,
            'country_options': list(countries),
            'find_courses_url': marketing_link('COURSES'),
            'language_options': settings.ALL_LANGUAGES,
            'badges_logo': staticfiles_storage.url('certificates/images/backpack-logo.png'),
            'badges_icon': staticfiles_storage.url('certificates/images/ico-mozillaopenbadges.png'),
            'backpack_ui_img': staticfiles_storage.url('certificates/images/backpack-ui.png'),
            'platform_name': microsite.get_value('platform_name', settings.PLATFORM_NAME),
        },
        'disable_courseware_js': True,
        'show_program_listing': ProgramsApiConfig.current().show_program_listing,
    }

    if badges_enabled():
        context['data']['badges_api_url'] = reverse("badges_api:user_assertions", kwargs={'username': profile_username})

    return context
Пример #22
0
    def test_is_student_dashboard_enabled(self, _mock_cache):
        """
        Ensure that is_student_dashboard_enabled only returns True when the
        current config has both 'enabled' and 'enable_student_dashboard' set to
        True.
        """
        self.assertFalse(ProgramsApiConfig.current().is_student_dashboard_enabled)

        self.create_config()
        self.assertFalse(ProgramsApiConfig.current().is_student_dashboard_enabled)

        self.create_config(enabled=True)
        self.assertFalse(ProgramsApiConfig.current().is_student_dashboard_enabled)

        self.create_config(enable_student_dashboard=True)
        self.assertFalse(ProgramsApiConfig.current().is_student_dashboard_enabled)

        self.create_config(enabled=True, enable_student_dashboard=True)
        self.assertTrue(ProgramsApiConfig.current().is_student_dashboard_enabled)
Пример #23
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

        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
        }

        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
Пример #24
0
def program_details(request, program_uuid):
    """View details about a specific program."""
    programs_config = ProgramsApiConfig.current()
    if not programs_config.enabled:
        raise Http404

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

    if not program_data:
        raise Http404

    program_data = ProgramDataExtender(program_data, request.user).extend()

    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'),
    }

    context = {
        'urls': urls,
        'show_program_listing': programs_config.enabled,
        'nav_hidden': True,
        'disable_courseware_js': True,
        'uses_pattern_library': True,
        'user_preferences': get_user_preferences(request.user)
    }

    if waffle.switch_is_active('new_program_progress'):
        course_data = meter.progress(programs=[program_data],
                                     count_only=False)[0]
        certificate_data = get_certificates(request.user, program_data)

        program_data.pop('courses')

        context.update({
            'program_data': program_data,
            'course_data': course_data,
            'certificate_data': certificate_data,
        })

        return render_to_response(
            'learner_dashboard/program_details_2017.html', context)
    else:
        context.update({'program_data': program_data})

        return render_to_response('learner_dashboard/program_details.html',
                                  context)
Пример #25
0
def set_cached_programs_response(programs_data):
    """ Set cache value for the programs data with specific ttl.

    Arguments:
        programs_data (dict): Programs data in dictionary format
    """
    cache.set(
        ProgramsApiConfig.PROGRAMS_API_CACHE_KEY,
        programs_data,
        ProgramsApiConfig.current().cache_ttl
    )
Пример #26
0
def view_programs(request):
    """View programs in which the user is engaged."""
    if not ProgramsApiConfig.current().is_student_dashboard_enabled:
        raise Http404

    enrollments = list(get_course_enrollments(request.user, None, []))
    programs = get_engaged_programs(request.user, enrollments)

    # TODO: Pull 'xseries' string from configuration model.
    marketing_root = urljoin(settings.MKTG_URLS.get('ROOT'), 'xseries').strip('/')
    for program in programs:
        program['marketing_url'] = '{root}/{slug}'.format(
            root=marketing_root,
            slug=program['marketing_slug']
        )

    return render_to_response('learner_dashboard/programs.html', {
        'programs': programs,
        'xseries_url': marketing_root if ProgramsApiConfig.current().show_xseries_ad else None
    })
Пример #27
0
    def _mock_programs_api(self):
        """Helper for mocking out Programs API URLs."""
        self.assertTrue(httpretty.is_enabled(), msg='httpretty must be enabled to mock Programs API calls.')

        url = '{api_root}/programs/{id}/'.format(
            api_root=ProgramsApiConfig.current().internal_api_url.strip('/'),
            id=self.program_id
        )
        body = json.dumps(self.data)

        httpretty.register_uri(httpretty.GET, url, body=body, content_type='application/json')
Пример #28
0
 def test_default_state(self, _mock_cache):
     """
     Ensure the config stores empty values when no data has been inserted,
     and is completely disabled.
     """
     self.assertFalse(ProgramsApiConfig.is_enabled())
     api_config = ProgramsApiConfig.current()
     self.assertEqual(api_config.internal_service_url, '')
     self.assertEqual(api_config.public_service_url, '')
     self.assertEqual(api_config.api_version_number, None)
     self.assertFalse(api_config.is_student_dashboard_enabled)
Пример #29
0
 def test_default_state(self, _mock_cache):
     """
     Ensure the config stores empty values when no data has been inserted,
     and is completely disabled.
     """
     self.assertFalse(ProgramsApiConfig.is_enabled())
     api_config = ProgramsApiConfig.current()
     self.assertEqual(api_config.internal_service_url, '')
     self.assertEqual(api_config.public_service_url, '')
     self.assertEqual(api_config.api_version_number, None)
     self.assertFalse(api_config.is_student_dashboard_enabled)
Пример #30
0
 def test_api_urls(self, _mock_cache):
     """
     Ensure the api url methods return correct concatenations of service
     URLs and version numbers.
     """
     self.create_config()
     api_config = ProgramsApiConfig.current()
     self.assertEqual(api_config.internal_api_url,
                      "{}api/v1/".format(self.INTERNAL_URL))
     self.assertEqual(api_config.public_api_url,
                      "{}api/v1/".format(self.PUBLIC_URL))
Пример #31
0
 def test_created_state(self, _mock_cache):
     """
     Ensure the config stores correct values when created with them, but
     remains disabled.
     """
     self.create_config()
     self.assertFalse(ProgramsApiConfig.is_enabled())
     api_config = ProgramsApiConfig.current()
     self.assertEqual(api_config.internal_service_url, self.INTERNAL_URL)
     self.assertEqual(api_config.public_service_url, self.PUBLIC_URL)
     self.assertEqual(api_config.api_version_number, 1)
     self.assertFalse(api_config.is_student_dashboard_enabled)
Пример #32
0
def public_program_listing(request):
    """View a list of all programs."""
    programs_config = ProgramsApiConfig.current()
    if not programs_config.show_program_listing:
        raise Http404

    meter = utils.ProgramProgressMeter(request.user)

    context = {
        'programs': meter.programs,
    }
    return render_to_response('learner_dashboard/public_programs.html', context)
Пример #33
0
 def test_created_state(self, _mock_cache):
     """
     Ensure the config stores correct values when created with them, but
     remains disabled.
     """
     self.create_config()
     self.assertFalse(ProgramsApiConfig.is_enabled())
     api_config = ProgramsApiConfig.current()
     self.assertEqual(api_config.internal_service_url, self.INTERNAL_URL)
     self.assertEqual(api_config.public_service_url, self.PUBLIC_URL)
     self.assertEqual(api_config.api_version_number, 1)
     self.assertFalse(api_config.is_student_dashboard_enabled)
Пример #34
0
def get_course_programs_for_dashboard(user, course_keys):   # pylint: disable=invalid-name
    """ Return all programs related to a user.

    Given a user and an iterable of course keys, find all
    the programs relevant to the user's dashboard and return them in a
    dictionary keyed by the course_key.

    Arguments:
        user (user object): Currently logged-in User for which we need to get
            JWT ID-Token
        course_keys (list): List of course keys in which user is enrolled

    Returns:
        Dictionary response containing programs or None
    """
    course_programs = {}
    if not is_student_dashboard_programs_enabled():
        log.warning("Programs service for student dashboard is disabled.")
        return course_programs

    # unicode-ify the course keys for efficient lookup
    course_keys = map(unicode, course_keys)

    # If cache config is enabled then get the response from cache first.
    if is_cache_enabled_for_programs():
        cached_programs = get_cached_programs_response()
        if cached_programs is not None:
            return _get_user_course_programs(cached_programs, course_keys)

    # get programs slumber-based client 'EdxRestApiClient'
    try:
        api_client = programs_api_client(ProgramsApiConfig.current().internal_api_url, get_id_token(user, CLIENT_NAME))
    except Exception:   # pylint: disable=broad-except
        log.exception('Failed to initialize the Programs API client.')
        return course_programs

    # get programs from api client
    try:
        response = api_client.programs.get()
    except Exception:  # pylint: disable=broad-except
        log.exception('Failed to retrieve programs from the Programs API.')
        return course_programs

    programs = response.get('results', [])
    if not programs:
        log.warning("No programs found for the user '%s'.", user.id)
        return course_programs

    # If cache config is enabled than set the cache.
    if is_cache_enabled_for_programs():
        set_cached_programs_response(programs)

    return _get_user_course_programs(programs, course_keys)
Пример #35
0
def view_programs(request):
    """View programs in which the user is engaged."""
    show_program_listing = ProgramsApiConfig.current().show_program_listing
    if not show_program_listing:
        raise Http404

    enrollments = list(get_course_enrollments(request.user, None, []))
    meter = ProgramProgressMeter(request.user, enrollments)
    programs = meter.engaged_programs

    # TODO: Pull 'xseries' string from configuration model.
    marketing_root = urljoin(settings.MKTG_URLS.get('ROOT'),
                             'xseries').strip('/')
    for program in programs:
        program['display_category'] = get_display_category(program)
        program['marketing_url'] = '{root}/{slug}'.format(
            root=marketing_root, slug=program['marketing_slug'])

    context = {
        'programs':
        programs,
        'progress':
        meter.progress,
        'xseries_url':
        marketing_root
        if ProgramsApiConfig.current().show_xseries_ad else None,
        'nav_hidden':
        True,
        'show_program_listing':
        show_program_listing,
        'credentials':
        get_programs_credentials(request.user, category='xseries'),
        'disable_courseware_js':
        True,
        'uses_pattern_library':
        True
    }

    return render_to_response('learner_dashboard/programs.html', context)
Пример #36
0
def program_details(request, program_uuid):  # pylint: disable=unused-argument
    """View programs in which the user is engaged."""
    show_program_details = ProgramsApiConfig.current().show_program_details
    if not show_program_details:
        raise Http404

    context = {
        'nav_hidden': True,
        'disable_courseware_js': True,
        'uses_pattern_library': True
    }

    return render_to_response('learner_dashboard/program_details.html', context)
Пример #37
0
    def mock_programs_api(self, data=None, status_code=200):
        """Utility for mocking out Programs API URLs."""
        self.assertTrue(httpretty.is_enabled(), msg='httpretty must be enabled to mock Programs API calls.')

        url = ProgramsApiConfig.current().internal_api_url.strip('/') + '/programs/'

        if data is None:
            data = self.PROGRAMS_API_RESPONSE

        body = json.dumps(data)

        httpretty.reset()
        httpretty.register_uri(httpretty.GET, url, body=body, content_type='application/json', status=status_code)
Пример #38
0
def view_programs(request):
    """View programs in which the user is engaged."""
    if not ProgramsApiConfig.current().is_student_dashboard_enabled:
        raise Http404

    enrollments = list(get_course_enrollments(request.user, None, []))
    programs = get_engaged_programs(request.user, enrollments)

    # TODO: Pull 'xseries' string from configuration model.
    marketing_root = urljoin(settings.MKTG_URLS.get('ROOT'),
                             'xseries').strip('/')
    for program in programs:
        program['marketing_url'] = '{root}/{slug}'.format(
            root=marketing_root, slug=program['marketing_slug'])

    return render_to_response(
        'learner_dashboard/programs.html', {
            'programs':
            programs,
            'xseries_url':
            marketing_root
            if ProgramsApiConfig.current().show_xseries_ad else None
        })
Пример #39
0
    def get(self, request, *args, **kwargs):
        """Populate the template context with values required for the authoring app to run."""
        programs_config = ProgramsApiConfig.current()

        if programs_config.is_studio_tab_enabled and request.user.is_staff:
            return render_to_response('program_authoring.html', {
                'lms_base_url': '//{}/'.format(settings.LMS_BASE),
                'programs_api_url': programs_config.public_api_url,
                'programs_token_url': reverse('programs_id_token'),
                'studio_home_url': reverse('home'),
                'uses_pattern_library': True
            })
        else:
            raise Http404
Пример #40
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

        program_data = ProgramDataExtender(program_data, request.user).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()

        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)
        }

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

        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
Пример #41
0
    def _mock_programs_api(self, data):
        """Helper for mocking out Programs API URLs."""
        self.assertTrue(
            httpretty.is_enabled(),
            msg='httpretty must be enabled to mock Programs API calls.')

        url = ProgramsApiConfig.current().internal_api_url.strip(
            '/') + '/programs/'
        body = json.dumps({'results': data})

        httpretty.register_uri(httpretty.GET,
                               url,
                               body=body,
                               content_type='application/json')
Пример #42
0
def program_details_marketing(request, program_id):
    """View details about a specific program."""

    programs_config = ProgramsApiConfig.current()
    if not programs_config.show_program_details:
        raise Http404

    auth_user = authenticate(
        username='******',
        password='******') if request.user.is_anonymous() else request.user

    try:
        # If the ID is a UUID, the requested program resides in the catalog.
        uuid.UUID(program_id)

        program_data = get_catalog_programs(auth_user, uuid=program_id)
        if program_data:
            program_data = munge_catalog_program(program_data)
    except ValueError:
        program_data = utils.get_programs(auth_user, program_id=program_id)

    if not program_data:
        raise Http404

    program_data = utils.ProgramDataExtender(program_data, auth_user).extend()

    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'),
    }

    context = {
        'program_data': program_data,
        'urls': urls,
        'show_program_listing': programs_config.show_program_listing,
        'nav_hidden': True,
        'disable_courseware_js': True,
        'uses_pattern_library': True,
        'user_preferences': get_user_preferences(auth_user)
    }

    return render_to_response(
        'learner_dashboard/program_details_marketing.html', context)
Пример #43
0
    def test_is_student_dashboard_enabled(self, _mock_cache):
        """
        Ensure that is_student_dashboard_enabled only returns True when the
        current config has both 'enabled' and 'enable_student_dashboard' set to
        True.
        """
        self.assertFalse(
            ProgramsApiConfig.current().is_student_dashboard_enabled)

        self.create_config()
        self.assertFalse(
            ProgramsApiConfig.current().is_student_dashboard_enabled)

        self.create_config(enabled=True)
        self.assertFalse(
            ProgramsApiConfig.current().is_student_dashboard_enabled)

        self.create_config(enable_student_dashboard=True)
        self.assertFalse(
            ProgramsApiConfig.current().is_student_dashboard_enabled)

        self.create_config(enabled=True, enable_student_dashboard=True)
        self.assertTrue(
            ProgramsApiConfig.current().is_student_dashboard_enabled)
Пример #44
0
    def _mock_programs_api(self):
        """Helper for mocking out Programs API URLs."""
        self.assertTrue(
            httpretty.is_enabled(),
            msg='httpretty must be enabled to mock Programs API calls.')

        url = '{api_root}/programs/{id}/'.format(
            api_root=ProgramsApiConfig.current().internal_api_url.strip('/'),
            id=self.program_id)
        body = json.dumps(self.data)

        httpretty.register_uri(httpretty.GET,
                               url,
                               body=body,
                               content_type='application/json')
Пример #45
0
def program_details(request, program_id):
    """View details about a specific program."""
    show_program_details = ProgramsApiConfig.current().show_program_details
    if not show_program_details:
        raise Http404

    program_data = utils.get_programs(request.user, program_id=program_id)

    if not program_data:
        raise Http404

    program_data = utils.supplement_program_data(program_data, request.user)
    show_program_listing = ProgramsApiConfig.current().show_program_listing

    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')
    }

    context = {
        'program_data': program_data,
        'urls': urls,
        'show_program_listing': show_program_listing,
        'nav_hidden': True,
        'disable_courseware_js': True,
        'uses_pattern_library': True
    }

    return render_to_response('learner_dashboard/program_details.html',
                              context)
Пример #46
0
def program_listing(request):
    """View a list of programs in which the user is engaged."""
    programs_config = ProgramsApiConfig.current()
    programs_fragment = ProgramsFragmentView().render_to_fragment(request, programs_config=programs_config)

    context = {
        'disable_courseware_js': True,
        'programs_fragment': programs_fragment,
        'nav_hidden': True,
        'show_dashboard_tabs': True,
        'show_program_listing': programs_config.enabled,
        'uses_bootstrap': True,
    }

    return render_to_response('learner_dashboard/programs.html', context)
Пример #47
0
def get_programs(user):
    """Given a user, get programs from the Programs service.

    Returned value is cached depending on user permissions. Staff users making requests
    against Programs will receive unpublished programs, while regular users will only receive
    published programs.

    Arguments:
        user (User): The user to authenticate as when requesting programs.

    Returns:
        list of dict, representing programs returned by the Programs service.
    """
    programs_config = ProgramsApiConfig.current()
    no_programs = []

    # Bypass caching for staff users, who may be creating Programs and want to see them displayed immediately.
    use_cache = programs_config.is_cache_enabled and not user.is_staff

    if not programs_config.enabled:
        log.warning('Programs configuration is disabled.')
        return no_programs

    if use_cache:
        cached = cache.get(programs_config.CACHE_KEY)
        if cached is not None:
            return cached

    try:
        jwt = get_id_token(user, programs_config.OAUTH2_CLIENT_NAME)
        api = EdxRestApiClient(programs_config.internal_api_url, jwt=jwt)
    except Exception:  # pylint: disable=broad-except
        log.exception('Failed to initialize the Programs API client.')
        return no_programs

    try:
        response = api.programs.get()
    except Exception:  # pylint: disable=broad-except
        log.exception('Failed to retrieve programs from the Programs API.')
        return no_programs

    results = response.get('results', no_programs)

    if use_cache:
        cache.set(programs_config.CACHE_KEY, results,
                  programs_config.cache_ttl)

    return results
Пример #48
0
def program_details(request, program_uuid):
    """View details about a specific program."""
    programs_config = ProgramsApiConfig.current()
    if not programs_config.enabled:
        raise Http404

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

    if not program_data:
        raise Http404

    program_data = ProgramDataExtender(program_data, request.user).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()

    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)
    }

    context = {
        'urls': urls,
        'show_program_listing': programs_config.enabled,
        'show_dashboard_tabs': True,
        'nav_hidden': True,
        'disable_courseware_js': True,
        'uses_pattern_library': True,
        'user_preferences': get_user_preferences(request.user),
        'program_data': program_data,
        'course_data': course_data,
        'certificate_data': certificate_data
    }

    return render_to_response('learner_dashboard/program_details.html',
                              context)
Пример #49
0
    def handle(self, *args, **options):
        programs_config = ProgramsApiConfig.current()
        self.client = Client.objects.get(name=programs_config.OAUTH2_CLIENT_NAME)

        if self.client.user is None:
            msg = (
                'No user is associated with the {} OAuth2 client. '
                'A service user is necessary to make requests to the Programs API. '
                'No tasks have been enqueued. '
                'Associate a user with the client and try again.'
            ).format(programs_config.OAUTH2_CLIENT_NAME)

            raise CommandError(msg)

        self._load_run_modes()

        logger.info('Looking for users who may be eligible for a program certificate.')

        self._load_usernames()

        if options.get('commit'):
            logger.info('Enqueuing program certification tasks for %d candidates.', len(self.usernames))
        else:
            logger.info(
                'Found %d candidates. To enqueue program certification tasks, pass the -c or --commit flags.',
                len(self.usernames)
            )
            return

        succeeded, failed = 0, 0
        for username in self.usernames:
            try:
                award_program_certificates.delay(username)
            except:  # pylint: disable=bare-except
                failed += 1
                logger.exception('Failed to enqueue task for user [%s]', username)
            else:
                succeeded += 1
                logger.debug('Successfully enqueued task for user [%s]', username)

        logger.info(
            'Done. Successfully enqueued tasks for %d candidates. '
            'Failed to enqueue tasks for %d candidates.',
            succeeded,
            failed
        )
Пример #50
0
def program_details(request, program_uuid):
    """View details about a specific program."""
    programs_config = ProgramsApiConfig.current()
    program_fragment = ProgramDetailsFragmentView().render_to_fragment(
        request, program_uuid, programs_config=programs_config)

    context = {
        'program_fragment': program_fragment,
        'show_program_listing': programs_config.enabled,
        'show_dashboard_tabs': True,
        'nav_hidden': True,
        'disable_courseware_js': True,
        'uses_bootstrap': True,
    }

    return render_to_response('learner_dashboard/program_details.html',
                              context)
Пример #51
0
    def get(self, request, *args, **kwargs):
        """Populate the template context with values required for the authoring app to run."""
        programs_config = ProgramsApiConfig.current()

        if programs_config.is_studio_tab_enabled and request.user.is_staff:
            return render_to_response(
                'program_authoring.html', {
                    'show_programs_header':
                    programs_config.is_studio_tab_enabled,
                    'authoring_app_config':
                    programs_config.authoring_app_config,
                    'programs_api_url': programs_config.public_api_url,
                    'programs_token_url': reverse('programs_id_token'),
                    'studio_home_url': reverse('home'),
                })
        else:
            raise Http404
Пример #52
0
def program_details(request, program_id):
    """View details about a specific program."""
    show_program_details = ProgramsApiConfig.current().show_program_details
    if not show_program_details:
        raise Http404

    program_data = get_programs(request.user, program_id=program_id)

    context = {
        'program_data': program_data,
        'nav_hidden': True,
        'disable_courseware_js': True,
        'uses_pattern_library': True
    }

    return render_to_response('learner_dashboard/program_details.html',
                              context)
Пример #53
0
def program_listing_marketing(request):
    """View a list of programs available in system"""
    programs_config = ProgramsApiConfig.current()
    if not programs_config.show_program_listing:
        raise Http404
    auth_user = authenticate(
        username='******',
        password='******') if request.user.is_anonymous() else request.user

    meter = utils.ProgramProgressMeter(auth_user)
    context = {
        'marketing_url': utils.get_program_marketing_url(programs_config),
        'programs': meter.programs,
    }

    return render_to_response('learner_dashboard/programs_marketing.html',
                              context)
Пример #54
0
def get_programs_for_dashboard(user, course_keys):
    """Build a dictionary of programs, keyed by course.

    Given a user and an iterable of course keys, find all the programs relevant
    to the user's dashboard and return them in a dictionary keyed by course key.

    Arguments:
        user (User): The user to authenticate as when requesting programs.
        course_keys (list): List of course keys representing the courses in which
            the given user has active enrollments.

    Returns:
        dict, containing programs keyed by course. Empty if programs cannot be retrieved.
    """
    programs_config = ProgramsApiConfig.current()
    course_programs = {}

    if not programs_config.is_student_dashboard_enabled:
        log.debug('Display of programs on the student dashboard is disabled.')
        return course_programs

    programs = get_programs(user)
    if not programs:
        log.debug('No programs found for the user with ID %d.', user.id)
        return course_programs

    # Convert course keys to Unicode representation for efficient lookup.
    course_keys = map(unicode, course_keys)

    # Reindex the result returned by the Programs API from:
    #     program -> course code -> course run
    # to:
    #     course run -> program_array
    # Ignore course runs not present in the user's active enrollments.
    for program in programs:
        try:
            for course_code in program['course_codes']:
                for run in course_code['run_modes']:
                    course_key = run['course_key']
                    if course_key in course_keys:
                        course_programs.setdefault(course_key, []).append(program)
        except KeyError:
            log.exception('Unable to parse Programs API response: %r', program)

    return course_programs
Пример #55
0
def get_programs(user):
    """Given a user, get programs from the Programs service.
    Returned value is cached depending on user permissions. Staff users making requests
    against Programs will receive unpublished programs, while regular users will only receive
    published programs.

    Arguments:
        user (User): The user to authenticate as when requesting programs.

    Returns:
        list of dict, representing programs returned by the Programs service.
    """
    programs_config = ProgramsApiConfig.current()

    # Bypass caching for staff users, who may be creating Programs and want
    # to see them displayed immediately.
    cache_key = programs_config.CACHE_KEY if programs_config.is_cache_enabled and not user.is_staff else None
    return get_edx_api_data(programs_config, user, 'programs', cache_key=cache_key)
Пример #56
0
def program_listing(request):
    """View a list of programs in which the user is engaged."""
    programs_config = ProgramsApiConfig.current()
    programs_fragment = ProgramsFragmentView().render_to_fragment(
        request, programs_config=programs_config)

    context = {
        'disable_courseware_js': True,
        'programs_fragment': programs_fragment,
        'nav_hidden': True,
        'show_dashboard_tabs': True,
        'show_program_listing': programs_config.enabled,
        'show_journal_listing':
        journals_enabled(),  # TODO: Dashboard Plugin required
        'uses_pattern_library': True,
    }

    return render_to_response('learner_dashboard/programs.html', context)
Пример #57
0
def get_program_detail_url(program, marketing_root):
    """Construct the URL to be used when linking to program details.

    Arguments:
        program (dict): Representation of a program.
        marketing_root (str): Root URL used to build links to program marketing pages.

    Returns:
        str, a link to program details
    """
    if ProgramsApiConfig.current().show_program_details:
        base = reverse('program_details_view', kwargs={'program_id': program['id']}).rstrip('/')
        slug = slugify(program['name'])
    else:
        base = marketing_root.rstrip('/')
        slug = program['marketing_slug']

    return '{base}/{slug}'.format(base=base, slug=slug)
Пример #58
0
    def post(self, request):
        if not ProgramsApiConfig.current().is_certification_enabled:
            return Response({'error': 'Program certification is disabled.'},
                            status=status.HTTP_400_BAD_REQUEST)

        username = request.data.get('username')
        if username:
            log.info('Enqueuing program certification task for user [%s]',
                     username)
            award_program_certificates.delay(username)

            return Response()
        else:
            return Response(
                {
                    'error':
                    'A username is required in order to issue program certificates.'
                },
                status=status.HTTP_400_BAD_REQUEST)
Пример #59
0
def program_listing(request):
    """View a list of programs in which the user is engaged."""
    programs_config = ProgramsApiConfig.current()
    if not programs_config.enabled:
        raise Http404

    meter = ProgramProgressMeter(request.user)

    context = {
        'disable_courseware_js': True,
        'marketing_url': get_program_marketing_url(programs_config),
        'nav_hidden': True,
        'programs': meter.engaged_programs,
        'progress': meter.progress(),
        'show_program_listing': programs_config.enabled,
        'uses_pattern_library': True,
    }

    return render_to_response('learner_dashboard/programs.html', context)
Пример #60
0
def handle_course_cert_awarded(sender, user, course_key, mode, status,
                               **kwargs):  # pylint: disable=unused-argument
    """
    If programs is enabled and a learner is awarded a course certificate,
    schedule a celery task to process any programs certificates for which
    the learner may now be eligible.

    Args:
        sender:
            class of the object instance that sent this signal
        user:
            django.contrib.auth.User - the user to whom a cert was awarded
        course_key:
            refers to the course run for which the cert was awarded
        mode:
            mode / certificate type, e.g. "verified"
        status:
            either "downloadable" or "generating"

    Returns:
        None

    """
    # Import here instead of top of file since this module gets imported before
    # the programs app is loaded, resulting in a Django deprecation warning.
    from openedx.core.djangoapps.programs.models import ProgramsApiConfig

    if not ProgramsApiConfig.current().is_certification_enabled:
        return

    # schedule background task to process
    LOGGER.debug(
        'handling COURSE_CERT_AWARDED: username=%s, course_key=%s, mode=%s, status=%s',
        user,
        course_key,
        mode,
        status,
    )
    # import here, because signal is registered at startup, but items in tasks are not yet able to be loaded
    from openedx.core.djangoapps.programs.tasks.v1.tasks import award_program_certificates
    award_program_certificates.delay(user.username)