Revert "MST-157 Create a new program enrollments inspector support tool to help edX support members to inspect the existing states of program enrollees"
This reverts commit 9bdcb9c5f5.
This commit is contained in:
@@ -1,57 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, InputText, StatusAlert, InputSelect } from '@edx/paragon';
|
||||
|
||||
export const ProgramEnrollmentsInspectorPage = props => (
|
||||
<form method="get">
|
||||
{props.successes.length > 0 && (
|
||||
<StatusAlert
|
||||
open
|
||||
alertType="success"
|
||||
dialog={(
|
||||
<div>
|
||||
<span></span>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div key="edX_accounts">
|
||||
<InputText
|
||||
name="edx_user"
|
||||
label="edX account username or email"
|
||||
value={(props.learnerInfo && props.learnerInfo.user && props.learnerInfo.user.username) || ''}
|
||||
/>
|
||||
</div>
|
||||
<div key="school_accounts">
|
||||
<InputSelect
|
||||
name="IdPSelect"
|
||||
label="Learner Account Providers"
|
||||
value="Select One"
|
||||
options={
|
||||
props.orgKeys
|
||||
}
|
||||
/>
|
||||
|
||||
<InputText
|
||||
name="external_user_key"
|
||||
label="Institution user key from school. For example, GTPersonDirectoryId for GT students"
|
||||
value={(props.learnerInfo && props.learnerInfo.user && props.learnerInfo.user.external_user_key) || ''}
|
||||
/>
|
||||
</div>
|
||||
<Button label="Search" type="submit" className={['btn', 'btn-primary']} />
|
||||
</form>
|
||||
);
|
||||
|
||||
ProgramEnrollmentsInspectorPage.propTypes = {
|
||||
successes: PropTypes.arrayOf(PropTypes.string),
|
||||
errors: PropTypes.arrayOf(PropTypes.string),
|
||||
learnerInfo: PropTypes.string,
|
||||
orgKeys: PropTypes.arrayOf(PropTypes.object),
|
||||
};
|
||||
|
||||
ProgramEnrollmentsInspectorPage.defaultProps = {
|
||||
successes: [],
|
||||
errors: [],
|
||||
learnerInfo: '',
|
||||
orgKeys: [],
|
||||
};
|
||||
@@ -8,7 +8,7 @@ import itertools
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
from uuid import UUID, uuid4
|
||||
from uuid import uuid4, UUID
|
||||
|
||||
import ddt
|
||||
import six
|
||||
@@ -17,19 +17,15 @@ from django.db.models import signals
|
||||
from django.http import HttpResponse
|
||||
from django.urls import reverse
|
||||
from mock import patch
|
||||
from organizations.tests.factories import OrganizationFactory
|
||||
from pytz import UTC
|
||||
from social_django.models import UserSocialAuth
|
||||
|
||||
from common.test.utils import disable_signal
|
||||
from course_modes.models import CourseMode
|
||||
from course_modes.tests.factories import CourseModeFactory
|
||||
from lms.djangoapps.program_enrollments.tests.factories import ProgramCourseEnrollmentFactory, ProgramEnrollmentFactory
|
||||
from lms.djangoapps.verify_student.models import VerificationDeadline
|
||||
from student.models import ENROLLED_TO_ENROLLED, CourseEnrollment, CourseEnrollmentAttribute, ManualEnrollmentAudit
|
||||
from student.roles import GlobalStaff, SupportStaffRole
|
||||
from student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from third_party_auth.tests.factories import SAMLProviderConfigFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
@@ -543,238 +539,3 @@ class SupportViewLinkProgramEnrollmentsTests(SupportViewTestCase):
|
||||
msg = u"All linking lines must be in the format 'external_user_key,lms_username'"
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert render_call_dict['errors'] == [msg]
|
||||
|
||||
|
||||
class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
"""
|
||||
View tests for Program Enrollments Inspector
|
||||
"""
|
||||
patch_render = patch(
|
||||
'support.views.program_enrollments.render_to_response',
|
||||
return_value=HttpResponse(),
|
||||
autospec=True,
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super(ProgramEnrollmentsInspectorViewTests, self).setUp()
|
||||
self.url = reverse("support:program_enrollments_inspector")
|
||||
SupportStaffRole().add_users(self.user)
|
||||
self.program_uuid = str(uuid4())
|
||||
self.external_user_key = 'abcaaa'
|
||||
# Setup three orgs and their SAML providers
|
||||
self.org_key_list = ['test_org', 'donut_org', 'tri_org']
|
||||
for org_key in self.org_key_list:
|
||||
lms_org = OrganizationFactory(
|
||||
short_name=org_key
|
||||
)
|
||||
SAMLProviderConfigFactory(
|
||||
organization=lms_org,
|
||||
slug=org_key,
|
||||
enabled=True,
|
||||
)
|
||||
self.no_saml_org_key = 'no_saml_org'
|
||||
self.no_saml_lms_org = OrganizationFactory(
|
||||
short_name=self.no_saml_org_key
|
||||
)
|
||||
|
||||
def _serialize_datetime(self, dt):
|
||||
return dt.strftime('%Y-%m-%dT%H:%M:%S')
|
||||
|
||||
def test_initial_rendering(self):
|
||||
response = self.client.get(self.url)
|
||||
content = six.text_type(response.content, encoding='utf-8')
|
||||
expected_organization_serialized = '"orgKeys": {}'.format(json.dumps(self.org_key_list))
|
||||
assert response.status_code == 200
|
||||
assert expected_organization_serialized in content
|
||||
assert '"learnerInfo": {}' in content
|
||||
|
||||
def _construct_user(self, username, org_key=None, external_user_key=None):
|
||||
"""
|
||||
Provided the username, create an edx account user. If the org_key is provided,
|
||||
SSO link the user with the IdP associated with org_key. Return the created user and
|
||||
expected user info object from the view
|
||||
"""
|
||||
user = UserFactory(username=username)
|
||||
user_info = {
|
||||
'username': user.username,
|
||||
'email': user.email
|
||||
}
|
||||
if org_key and external_user_key:
|
||||
user_social_auth = UserSocialAuth.objects.create(
|
||||
user=user,
|
||||
uid='{0}:{1}'.format(org_key, external_user_key),
|
||||
provider=org_key
|
||||
)
|
||||
user_info['external_user_key'] = external_user_key
|
||||
user_info['SSO'] = {
|
||||
'uid': user_social_auth.uid,
|
||||
'provider': user_social_auth.provider
|
||||
}
|
||||
return user, user_info
|
||||
|
||||
def _construct_enrollments(self, program_uuids, course_ids, external_user_key, edx_user=None):
|
||||
"""
|
||||
A helper function to setup the program enrollments for a given learner.
|
||||
If the edx user is provided, it will try to SSO the user with the enrollments
|
||||
Return the expected info object that should be created based on the model setup
|
||||
"""
|
||||
expected_enrollments = []
|
||||
for program_uuid in program_uuids:
|
||||
expected_enrollment = {}
|
||||
expected_course_enrollment = {}
|
||||
course_enrollment = None
|
||||
program_enrollment = ProgramEnrollmentFactory.create(
|
||||
external_user_key=external_user_key,
|
||||
program_uuid=program_uuid,
|
||||
user=edx_user
|
||||
)
|
||||
expected_enrollment['program_enrollment'] = {
|
||||
'created': self._serialize_datetime(
|
||||
program_enrollment.created
|
||||
),
|
||||
'modified': self._serialize_datetime(
|
||||
program_enrollment.modified
|
||||
),
|
||||
'program_uuid': program_enrollment.program_uuid,
|
||||
'external_user_key': external_user_key,
|
||||
'status': program_enrollment.status
|
||||
}
|
||||
|
||||
for course_id in course_ids:
|
||||
if edx_user:
|
||||
course_enrollment = CourseEnrollmentFactory.create(
|
||||
course_id=course_id,
|
||||
user=edx_user,
|
||||
mode=CourseMode.MASTERS,
|
||||
is_active=True
|
||||
)
|
||||
expected_course_enrollment = {
|
||||
'course_id': str(course_enrollment.course_id),
|
||||
'is_active': course_enrollment.is_active,
|
||||
'mode': course_enrollment.mode,
|
||||
}
|
||||
|
||||
program_course_enrollment = ProgramCourseEnrollmentFactory.create(
|
||||
program_enrollment=program_enrollment,
|
||||
course_key=course_id,
|
||||
course_enrollment=course_enrollment,
|
||||
status='active',
|
||||
)
|
||||
expected_program_course_enrollment = {
|
||||
'created': self._serialize_datetime(
|
||||
program_course_enrollment.created
|
||||
),
|
||||
'modified': self._serialize_datetime(
|
||||
program_course_enrollment.modified
|
||||
),
|
||||
'status': program_course_enrollment.status,
|
||||
'course_key': str(program_course_enrollment.course_key),
|
||||
}
|
||||
if expected_course_enrollment:
|
||||
expected_program_course_enrollment['course_enrollment'] = expected_course_enrollment
|
||||
|
||||
expected_enrollment.setdefault('program_course_enrollments', []).append(
|
||||
expected_program_course_enrollment
|
||||
)
|
||||
|
||||
expected_enrollments.append(expected_enrollment)
|
||||
|
||||
return expected_enrollments
|
||||
|
||||
@patch_render
|
||||
def test_search_username_well_connected_user(self, mocked_render):
|
||||
created_user, expected_user_info = self._construct_user(
|
||||
'test_user_connected',
|
||||
self.org_key_list[0],
|
||||
self.external_user_key
|
||||
)
|
||||
expected_enrollments = self._construct_enrollments(
|
||||
[self.program_uuid],
|
||||
[self.course.id],
|
||||
self.external_user_key,
|
||||
created_user
|
||||
)
|
||||
self.client.get(self.url, data={
|
||||
'edx_user': created_user.username
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info,
|
||||
'enrollments': expected_enrollments
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert expected_info == render_call_dict['learner_program_enrollments']
|
||||
|
||||
@patch_render
|
||||
def test_search_username_user_not_connected(self, mocked_render):
|
||||
created_user, expected_user_info = self._construct_user('user_not_connected')
|
||||
self.client.get(self.url, data={
|
||||
'edx_user': created_user.email
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert expected_info == render_call_dict['learner_program_enrollments']
|
||||
|
||||
@patch_render
|
||||
def test_search_username_user_no_enrollment(self, mocked_render):
|
||||
created_user, expected_user_info = self._construct_user(
|
||||
'user_connected',
|
||||
self.org_key_list[0],
|
||||
self.external_user_key
|
||||
)
|
||||
self.client.get(self.url, data={
|
||||
'edx_user': created_user.email
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert expected_info == render_call_dict['learner_program_enrollments']
|
||||
|
||||
@patch_render
|
||||
def test_search_username_user_no_course_enrollment(self, mocked_render):
|
||||
created_user, expected_user_info = self._construct_user(
|
||||
'user_connected',
|
||||
self.org_key_list[0],
|
||||
self.external_user_key
|
||||
)
|
||||
expected_enrollments = self._construct_enrollments(
|
||||
[self.program_uuid],
|
||||
[],
|
||||
self.external_user_key,
|
||||
created_user,
|
||||
)
|
||||
self.client.get(self.url, data={
|
||||
'edx_user': created_user.email
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info,
|
||||
'enrollments': expected_enrollments
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert expected_info == render_call_dict['learner_program_enrollments']
|
||||
|
||||
@patch_render
|
||||
def test_search_username_user_not_connected_with_enrollments(self, mocked_render):
|
||||
created_user, expected_user_info = self._construct_user(
|
||||
'user_not_connected'
|
||||
)
|
||||
self._construct_enrollments(
|
||||
[self.program_uuid],
|
||||
[],
|
||||
self.external_user_key,
|
||||
)
|
||||
self.client.get(self.url, data={
|
||||
'edx_user': created_user.email
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info,
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert expected_info == render_call_dict['learner_program_enrollments']
|
||||
|
||||
@@ -12,8 +12,8 @@ from support.views.enrollments import EnrollmentSupportListView, EnrollmentSuppo
|
||||
from support.views.feature_based_enrollments import FeatureBasedEnrollmentsSupportView
|
||||
from support.views.index import index
|
||||
from support.views.manage_user import ManageUserDetailView, ManageUserSupportView
|
||||
from support.views.program_enrollments import LinkProgramEnrollmentSupportView, ProgramEnrollmentsInspectorView
|
||||
from support.views.refund import RefundSupportView
|
||||
from support.views.program_enrollments import LinkProgramEnrollmentSupportView
|
||||
|
||||
COURSE_ENTITLEMENTS_VIEW = EntitlementSupportView.as_view()
|
||||
|
||||
@@ -41,10 +41,5 @@ urlpatterns = [
|
||||
FeatureBasedEnrollmentsSupportView.as_view(),
|
||||
name="feature_based_enrollments"
|
||||
),
|
||||
url(r'link_program_enrollments/?$', LinkProgramEnrollmentSupportView.as_view(), name='link_program_enrollments'),
|
||||
url(
|
||||
r'program_enrollments_inspector/?$',
|
||||
ProgramEnrollmentsInspectorView.as_view(),
|
||||
name='program_enrollments_inspector'
|
||||
)
|
||||
url(r'link_program_enrollments/?$', LinkProgramEnrollmentSupportView.as_view(), name='link_program_enrollments')
|
||||
]
|
||||
|
||||
@@ -3,9 +3,9 @@ Certificate tool in the student support app.
|
||||
"""
|
||||
|
||||
|
||||
from six.moves.urllib.parse import unquote, quote_plus # pylint: disable=import-error
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.generic import View
|
||||
from six.moves.urllib.parse import quote_plus, unquote
|
||||
|
||||
from edxmako.shortcuts import render_to_response
|
||||
from support.decorators import require_support_permission
|
||||
|
||||
@@ -6,22 +6,14 @@ Support tool for changing course enrollments.
|
||||
import csv
|
||||
from uuid import UUID
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import Q
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.generic import View
|
||||
from social_django.models import UserSocialAuth
|
||||
|
||||
from edxmako.shortcuts import render_to_response
|
||||
from lms.djangoapps.program_enrollments.api import (
|
||||
fetch_program_enrollments_by_student,
|
||||
link_program_enrollments
|
||||
)
|
||||
from lms.djangoapps.program_enrollments.api import link_program_enrollments
|
||||
from lms.djangoapps.support.decorators import require_support_permission
|
||||
from third_party_auth.models import SAMLProviderConfig
|
||||
|
||||
TEMPLATE_PATH = 'support/link_program_enrollments.html'
|
||||
DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S'
|
||||
|
||||
|
||||
class LinkProgramEnrollmentSupportView(View):
|
||||
@@ -106,153 +98,3 @@ class LinkProgramEnrollmentSupportView(View):
|
||||
]
|
||||
errors = [message for message in link_errors.values()]
|
||||
return successes, errors
|
||||
|
||||
|
||||
class ProgramEnrollmentsInspectorView(View):
|
||||
"""
|
||||
The view to search and display the program enrollments
|
||||
information of a learner.
|
||||
"""
|
||||
exclude_from_schema = True
|
||||
CONSOLE_TEMPLATE_PATH = 'support/program_enrollments_inspector.html'
|
||||
|
||||
@method_decorator(require_support_permission)
|
||||
def get(self, request):
|
||||
"""
|
||||
Based on the query string parameters passed through the GET request
|
||||
Search the data store for information about ProgramEnrollment and
|
||||
SSO linkage with the user.
|
||||
"""
|
||||
errors = []
|
||||
edx_username_or_email = request.GET.get('edx_user', '').strip()
|
||||
org_key = request.GET.get('IdPSelect', '').strip()
|
||||
external_user_key = request.GET.get('external_user_key', '').strip()
|
||||
learner_program_enrollments = {}
|
||||
if edx_username_or_email:
|
||||
learner_program_enrollments, error = self._get_account_info(edx_username_or_email)
|
||||
if error:
|
||||
errors.append(error)
|
||||
elif org_key and external_user_key:
|
||||
learner_program_enrollments = {}
|
||||
elif not external_user_key and org_key:
|
||||
errors.append(
|
||||
'You must provide either the edX username or email, or the '
|
||||
'Learner Account Provider and External Key pair to do search!'
|
||||
)
|
||||
|
||||
return render_to_response(
|
||||
self.CONSOLE_TEMPLATE_PATH,
|
||||
{
|
||||
'successes': [],
|
||||
'errors': errors,
|
||||
'learner_program_enrollments': learner_program_enrollments,
|
||||
'org_keys': self._get_org_keys_with_idp(),
|
||||
}
|
||||
)
|
||||
|
||||
def _get_org_keys_with_idp(self):
|
||||
"""
|
||||
From our Third_party_auth models, return a list
|
||||
of organizations whose SAMLProviders are active and configured
|
||||
"""
|
||||
saml_providers = SAMLProviderConfig.objects.current_set().filter(
|
||||
enabled=True,
|
||||
organization__isnull=False
|
||||
).select_related('organization')
|
||||
|
||||
return [saml_provider.organization.short_name for saml_provider in saml_providers]
|
||||
|
||||
def _get_account_info(self, username_or_email):
|
||||
"""
|
||||
Provided the edx account username or email, return edx account info
|
||||
and program_enrollments_info. If we cannot identify the user, return
|
||||
empty object and error.
|
||||
"""
|
||||
user_info = {}
|
||||
external_key = None
|
||||
try:
|
||||
user = User.objects.get(Q(username=username_or_email) | Q(email=username_or_email))
|
||||
user_info['username'] = user.username
|
||||
user_info['email'] = user.email
|
||||
try:
|
||||
user_social_auth = UserSocialAuth.objects.get(user=user)
|
||||
_, external_key = user_social_auth.uid.split(':', 1)
|
||||
user_info['external_user_key'] = external_key
|
||||
user_info['SSO'] = {
|
||||
'uid': user_social_auth.uid,
|
||||
'provider': user_social_auth.provider
|
||||
}
|
||||
except UserSocialAuth.DoesNotExist:
|
||||
pass
|
||||
|
||||
enrollments = self._get_enrollments(user=user)
|
||||
result = {'user': user_info}
|
||||
if enrollments:
|
||||
result['enrollments'] = enrollments
|
||||
|
||||
return result, ''
|
||||
except User.DoesNotExist:
|
||||
return {}, 'Could not find edx account with {}'.format(username_or_email)
|
||||
|
||||
def _get_enrollments(self, user=None, external_user_key=None):
|
||||
"""
|
||||
With the user or external_user_key passed in,
|
||||
return an array of dictionariers with corresponding ProgramEnrollments
|
||||
and ProgramCourseEnrollments all serialized for view
|
||||
"""
|
||||
program_enrollments = fetch_program_enrollments_by_student(
|
||||
user=user,
|
||||
external_user_key=external_user_key
|
||||
).prefetch_related('program_course_enrollments')
|
||||
|
||||
enrollments_by_program_uuid = {}
|
||||
for program_enrollment in program_enrollments:
|
||||
serialized_program_enrollment = self._serialize_program_enrollment(program_enrollment)
|
||||
enrollment_item = {
|
||||
'program_enrollment': serialized_program_enrollment
|
||||
}
|
||||
program_course_enrollments = program_enrollment.program_course_enrollments.all()
|
||||
for program_course_enrollment in program_course_enrollments.select_related(
|
||||
'course_enrollment'
|
||||
):
|
||||
serialized_program_course_enrollment = self._serialize_program_course_enrollment(
|
||||
program_course_enrollment
|
||||
)
|
||||
enrollment_item.setdefault('program_course_enrollments', []).append(
|
||||
serialized_program_course_enrollment
|
||||
)
|
||||
enrollments_by_program_uuid[program_enrollment.program_uuid] = enrollment_item
|
||||
|
||||
return list(enrollments_by_program_uuid.values())
|
||||
|
||||
def _serialize_program_enrollment(self, program_enrollment):
|
||||
if not program_enrollment:
|
||||
return {}
|
||||
|
||||
return {
|
||||
'created': program_enrollment.created.strftime(DATETIME_FORMAT),
|
||||
'modified': program_enrollment.modified.strftime(DATETIME_FORMAT),
|
||||
'program_uuid': str(program_enrollment.program_uuid),
|
||||
'external_user_key': program_enrollment.external_user_key,
|
||||
'status': program_enrollment.status
|
||||
}
|
||||
|
||||
def _serialize_program_course_enrollment(self, program_course_enrollment):
|
||||
"""
|
||||
Return a dictionary of ProgramCourseEnrollment serialized
|
||||
"""
|
||||
if not program_course_enrollment:
|
||||
return {}
|
||||
|
||||
course_enrollment = program_course_enrollment.course_enrollment
|
||||
return {
|
||||
'created': program_course_enrollment.created.strftime(DATETIME_FORMAT),
|
||||
'modified': program_course_enrollment.modified.strftime(DATETIME_FORMAT),
|
||||
'course_enrollment': {
|
||||
'course_id': str(course_enrollment.course_id),
|
||||
'is_active': course_enrollment.is_active,
|
||||
'mode': course_enrollment.mode,
|
||||
},
|
||||
'status': program_course_enrollment.status,
|
||||
'course_key': str(program_course_enrollment.course_key),
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<%page expression_filter="h"/>
|
||||
|
||||
<%!
|
||||
from django.utils.translation import ugettext as _
|
||||
from openedx.core.djangolib.js_utils import js_escaped_string
|
||||
%>
|
||||
|
||||
## Override the default styles_version to use Bootstrap
|
||||
<%! main_css = "css/bootstrap/lms-main.css" %>
|
||||
|
||||
<%namespace name='static' file='../static_content.html'/>
|
||||
|
||||
<%inherit file="../main.html" />
|
||||
|
||||
<%block name="js_extra">
|
||||
</%block>
|
||||
|
||||
<%block name="pagetitle">
|
||||
${_("Program Enrollments Inspector")}
|
||||
</%block>
|
||||
|
||||
<%block name="content">
|
||||
<section class="container outside-app">
|
||||
<h3> Program Enrollments Inspector </h3>
|
||||
${static.renderReact(
|
||||
component="ProgramEnrollmentsInspectorPage",
|
||||
id="entitlement-support-page",
|
||||
props={
|
||||
'successes': successes,
|
||||
'errors': errors,
|
||||
'learnerInfo': learner_program_enrollments,
|
||||
'orgKeys': org_keys
|
||||
}
|
||||
)
|
||||
}
|
||||
</section>
|
||||
</%block>
|
||||
@@ -86,8 +86,6 @@ module.exports = Merge.smart({
|
||||
EntitlementSupportPage: './lms/djangoapps/support/static/support/jsx/entitlements/index.jsx',
|
||||
LinkProgramEnrollmentsSupportPage: './lms/djangoapps/support/static/support/jsx/' +
|
||||
'program_enrollments/index.jsx',
|
||||
ProgramEnrollmentsInspectorPage: './lms/djangoapps/support/static/support/jsx/' +
|
||||
'program_enrollments/inspector.jsx',
|
||||
PasswordResetConfirmation: './lms/static/js/student_account/components/PasswordResetConfirmation.jsx',
|
||||
StudentAccountDeletion: './lms/static/js/student_account/components/StudentAccountDeletion.jsx',
|
||||
StudentAccountDeletionInitializer: './lms/static/js/student_account/StudentAccountDeletionInitializer.js',
|
||||
|
||||
Reference in New Issue
Block a user