feat: add stacked config model for disabling the frontend-app-learning progress page

This commit is contained in:
Matthew Piatetsky
2021-05-26 14:52:46 -04:00
parent 4d8abcac00
commit e6268470b8
8 changed files with 143 additions and 1 deletions

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

View File

@@ -0,0 +1,9 @@
"""
Course home api application configuration
"""
from django.apps import AppConfig
class CourseHomeApiConfig(AppConfig):
name = 'lms.djangoapps.course_home_api'

View 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'),
),
]

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

View File

@@ -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

View File

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

View File

@@ -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',