Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion common/djangoapps/student/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


from functools import wraps
from dal import autocomplete

from config_models.admin import ConfigurationModelAdmin
from django import forms
Expand All @@ -16,7 +17,7 @@
from django.db import models, router, transaction
from django.http import HttpResponseRedirect
from django.http.request import QueryDict
from django.urls import reverse
from django.urls import reverse, path
from django.utils.translation import ngettext
from django.utils.translation import gettext_lazy as _
from opaque_keys import InvalidKeyError
Expand Down Expand Up @@ -45,6 +46,7 @@
UserProfile,
UserTestGroup
)
from common.djangoapps.student.constants import LANGUAGE_CHOICES
from common.djangoapps.student.roles import REGISTERED_ACCESS_ROLES
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order

Expand Down Expand Up @@ -309,9 +311,25 @@ def get_queryset(self, request):
return super().get_queryset(request).select_related('user') # lint-amnesty, pylint: disable=no-member, super-with-arguments


class LanguageAutocomplete(autocomplete.Select2ListView):
def get_list(self):
return [lang for lang in LANGUAGE_CHOICES if self.q.lower() in lang.lower()]

class UserProfileInlineForm(forms.ModelForm):
language = forms.CharField(
required=False,
widget=autocomplete.ListSelect2(url='admin:language-autocomplete')
)

class Meta:
model = UserProfile
fields = '__all__'


class UserProfileInline(admin.StackedInline):
""" Inline admin interface for UserProfile model. """
model = UserProfile
form = UserProfileInlineForm
can_delete = False
verbose_name_plural = _('User profile')

Expand Down Expand Up @@ -359,6 +377,17 @@ def get_readonly_fields(self, request, obj=None):
return django_readonly + ('username',)
return django_readonly

def get_urls(self):
urls = super().get_urls()
custom_urls = [
path(
'language-autocomplete/',
LanguageAutocomplete.as_view(),
name='language-autocomplete'
),
]
return custom_urls + urls


@admin.register(UserAttribute)
class UserAttributeAdmin(admin.ModelAdmin):
Expand Down
3 changes: 3 additions & 0 deletions common/djangoapps/student/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import pycountry

LANGUAGE_CHOICES = sorted({lang.name for lang in pycountry.languages if hasattr(lang, 'alpha_2')})
3 changes: 3 additions & 0 deletions lms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3042,6 +3042,9 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring
'django.contrib.sessions',
'django.contrib.sites',

'dal',
'dal_select2',

# Tweaked version of django.contrib.staticfiles
'openedx.core.djangoapps.staticfiles.apps.EdxPlatformStaticFilesConfig',

Expand Down
77 changes: 76 additions & 1 deletion openedx/core/djangoapps/site_configuration/admin.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,81 @@
"""
Django admin page for Site Configuration models
"""
from dal import autocomplete


from django import forms
from django.urls import path
from django.utils.translation import gettext_lazy as _
from django.contrib import admin

from .constants import FEATURE_FLAGS
from .models import SiteConfiguration, SiteConfigurationHistory

class FeatureFlagAutocomplete(autocomplete.Select2ListView):
def get_list(self):
return list(FEATURE_FLAGS.keys())

def get_result_label(self, item):
return item

def get_result_value(self, item):
return item

class SiteConfigurationForm(forms.ModelForm):
feature_flags = forms.Field(
required=False,
widget=autocomplete.Select2Multiple(
url='admin:feature-flag-autocomplete',
attrs={
'multiple': 'multiple',
'data-tags': 'true',
'data-placeholder': 'Select features'
}
),
label="Enabled Features",
)

class Meta:
model = SiteConfiguration
fields = '__all__'

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

self.fields['site_values'].widget = forms.HiddenInput()
current_values = self.instance.site_values or {}
selected_labels = []
for label, mapping in FEATURE_FLAGS.items():
if all(current_values.get(k) == v for k, v in mapping.items()):
selected_labels.append(label)

self.fields['feature_flags'].initial = selected_labels
self.fields['feature_flags'].widget.choices = [(v, v) for v in selected_labels]


def clean(self):
cleaned = super().clean()

selected_flags = self.data.getlist('feature_flags')
if not isinstance(selected_flags, list):
selected_flags = [selected_flags] if selected_flags else []

site_values = {}
for label in selected_flags:
site_values.update(FEATURE_FLAGS.get(label, {}))

cleaned['feature_flags'] = selected_flags
cleaned['site_values'] = site_values
# self.selected_flags = selected_flags
# self.site_values = site_values

return cleaned

class SiteConfigurationAdmin(admin.ModelAdmin):
"""
Admin interface for the SiteConfiguration object.
"""
form = SiteConfigurationForm
list_display = ('site', 'enabled', 'site_values')
search_fields = ('site__domain', 'site_values')

Expand All @@ -21,6 +85,17 @@ class Meta:
"""
model = SiteConfiguration

def get_urls(self):
urls = super().get_urls()
custom_urls = [
path(
'feature-flag-autocomplete/',
FeatureFlagAutocomplete.as_view(),
name='feature-flag-autocomplete'
),
]
return custom_urls + urls

admin.site.register(SiteConfiguration, SiteConfigurationAdmin)


Expand Down
6 changes: 6 additions & 0 deletions openedx/core/djangoapps/site_configuration/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# TODO: Dummy Tags to be replaced by real values
FEATURE_FLAGS = {
'Forum Notifications': {'enable_forum_notifications': True},
'Live Chat': {'enable_live_chat': True},
'Dark Mode': {'enable_dark_mode': True},
}