feat: add stacked config model for disabling the frontend-app-learning progress page
This commit is contained in:
41
lms/djangoapps/course_home_api/admin.py
Normal file
41
lms/djangoapps/course_home_api/admin.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""
|
||||
Django Admin for DisableProgressPageStackedConfig.
|
||||
"""
|
||||
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from openedx.core.djangoapps.config_model_utils.admin import StackedConfigModelAdmin
|
||||
|
||||
from .models import DisableProgressPageStackedConfig
|
||||
|
||||
|
||||
class DisableProgressPageStackedConfigAdmin(StackedConfigModelAdmin):
|
||||
"""
|
||||
Stacked Config Model Admin for disable the progress page
|
||||
"""
|
||||
fieldsets = (
|
||||
('Context', {
|
||||
'fields': DisableProgressPageStackedConfig.KEY_FIELDS,
|
||||
'description': _(
|
||||
'These define the context to disable the frontend-app-learning progress page.'
|
||||
'If no values are set, then the configuration applies globally. '
|
||||
'If a single value is set, then the configuration applies to all courses '
|
||||
'within that context. At most one value can be set at a time.<br>'
|
||||
'If multiple contexts apply to a course (for example, if configuration '
|
||||
'is specified for the course specifically, and for the org that the course '
|
||||
'is in, then the more specific context overrides the more general context.'
|
||||
),
|
||||
}),
|
||||
('Configuration', {
|
||||
'fields': ('disabled',),
|
||||
'description': _(
|
||||
'If any of these values is left empty or "Unknown", then their value '
|
||||
'at runtime will be retrieved from the next most specific context that applies. '
|
||||
'For example, if "Disabled" is left as "Unknown" in the course context, then that '
|
||||
'course will be Disabled only if the org that it is in is Disabled.'
|
||||
),
|
||||
})
|
||||
)
|
||||
|
||||
admin.site.register(DisableProgressPageStackedConfig, DisableProgressPageStackedConfigAdmin)
|
||||
9
lms/djangoapps/course_home_api/apps.py
Normal file
9
lms/djangoapps/course_home_api/apps.py
Normal file
@@ -0,0 +1,9 @@
|
||||
"""
|
||||
Course home api application configuration
|
||||
"""
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CourseHomeApiConfig(AppConfig):
|
||||
name = 'lms.djangoapps.course_home_api'
|
||||
45
lms/djangoapps/course_home_api/migrations/0001_initial.py
Normal file
45
lms/djangoapps/course_home_api/migrations/0001_initial.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Generated by Django 2.2.20 on 2021-05-26 17:41
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import openedx.core.djangoapps.config_model_utils.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('sites', '0002_alter_domain_unique'),
|
||||
('course_overviews', '0024_overview_adds_has_highlights'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='DisableProgressPageStackedConfig',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
|
||||
('enabled', models.NullBooleanField(default=None, verbose_name='Enabled')),
|
||||
('org', models.CharField(blank=True, db_index=True, help_text='Configure values for all course runs associated with this Organization. This is the organization string (i.e. edX, MITx).', max_length=255, null=True)),
|
||||
('org_course', models.CharField(blank=True, db_index=True, help_text="Configure values for all course runs associated with this course. This is should be formatted as 'org+course' (i.e. MITx+6.002x, HarvardX+CS50).", max_length=255, null=True, validators=[openedx.core.djangoapps.config_model_utils.models.validate_course_in_org], verbose_name='Course in Org')),
|
||||
('disabled', models.NullBooleanField(default=None, verbose_name='Disabled')),
|
||||
('changed_by', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='Changed by')),
|
||||
('course', models.ForeignKey(blank=True, help_text='Configure values for this course run. This should be formatted as the CourseKey (i.e. course-v1://MITx+6.002x+2019_Q1)', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='course_overviews.CourseOverview', verbose_name='Course Run')),
|
||||
('site', models.ForeignKey(blank=True, help_text='Configure values for all course runs associated with this site.', null=True, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='disableprogresspagestackedconfig',
|
||||
index=models.Index(fields=['site', 'org', 'course'], name='course_home_site_id_6988e4_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='disableprogresspagestackedconfig',
|
||||
index=models.Index(fields=['site', 'org', 'org_course', 'course'], name='course_home_site_id_23dec6_idx'),
|
||||
),
|
||||
]
|
||||
25
lms/djangoapps/course_home_api/models.py
Normal file
25
lms/djangoapps/course_home_api/models.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""
|
||||
Course home api models file
|
||||
"""
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from openedx.core.djangoapps.config_model_utils.models import StackedConfigurationModel
|
||||
|
||||
|
||||
class DisableProgressPageStackedConfig(StackedConfigurationModel):
|
||||
"""
|
||||
Stacked Config Model for disabling the frontend-app-learning progress page
|
||||
"""
|
||||
|
||||
STACKABLE_FIELDS = ('disabled',)
|
||||
# Since this config disables the progress page,
|
||||
# it seemed it would be clearer to use a disabled flag instead of an enabled flag.
|
||||
# The enabled field still exists but is not used or shown in the admin.
|
||||
disabled = models.NullBooleanField(default=None, verbose_name=_("Disabled"))
|
||||
|
||||
def __str__(self):
|
||||
return "DisableProgressPageStackedConfig(disabled={!r})".format(
|
||||
self.disabled
|
||||
)
|
||||
@@ -16,9 +16,11 @@ from common.djangoapps.course_modes.models import CourseMode
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests
|
||||
from lms.djangoapps.course_home_api.models import DisableProgressPageStackedConfig
|
||||
from lms.djangoapps.course_home_api.toggles import COURSE_HOME_MICROFRONTEND, COURSE_HOME_MICROFRONTEND_PROGRESS_TAB
|
||||
from lms.djangoapps.experiments.testutils import override_experiment_waffle_flag
|
||||
from lms.djangoapps.verify_student.models import ManualVerification
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.course_date_signals.utils import MIN_DURATION
|
||||
from openedx.core.djangoapps.user_api.preferences.api import set_user_preference
|
||||
from openedx.features.course_duration_limits.models import CourseDurationLimitConfig
|
||||
@@ -155,3 +157,17 @@ class ProgressTabTestViews(BaseCourseHomeTests):
|
||||
assert response.data['verified_mode'] == {'access_expiration_date': (enrollment.created + MIN_DURATION),
|
||||
'currency': 'USD', 'currency_symbol': '$', 'price': 149,
|
||||
'sku': 'ABCD1234', 'upgrade_url': '/dashboard'}
|
||||
|
||||
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
|
||||
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_PROGRESS_TAB, active=True)
|
||||
def test_page_respects_stacked_config(self):
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
course_overview = CourseOverview.get_from_id(self.course.id)
|
||||
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
|
||||
DisableProgressPageStackedConfig.objects.create(disabled=True, course=course_overview)
|
||||
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 404
|
||||
|
||||
@@ -51,7 +51,10 @@ def course_home_mfe_outline_tab_is_active(course_key):
|
||||
|
||||
|
||||
def course_home_mfe_progress_tab_is_active(course_key):
|
||||
# Avoiding a circular dependency
|
||||
from .models import DisableProgressPageStackedConfig
|
||||
return (
|
||||
course_home_mfe_is_active(course_key) and
|
||||
COURSE_HOME_MICROFRONTEND_PROGRESS_TAB.is_enabled(course_key)
|
||||
COURSE_HOME_MICROFRONTEND_PROGRESS_TAB.is_enabled(course_key) and
|
||||
not DisableProgressPageStackedConfig.current(course_key=course_key).disabled
|
||||
)
|
||||
|
||||
@@ -2866,6 +2866,9 @@ INSTALLED_APPS = [
|
||||
'lms.djangoapps.bulk_email',
|
||||
'lms.djangoapps.branding',
|
||||
|
||||
# Course home api
|
||||
'lms.djangoapps.course_home_api',
|
||||
|
||||
# New (Blockstore-based) XBlock runtime
|
||||
'openedx.core.djangoapps.xblock.apps.LmsXBlockAppConfig',
|
||||
|
||||
|
||||
Reference in New Issue
Block a user