Merge pull request #33530 from openedx/dkaplan1/APER-2407_remove-coaching-functionality-from-edx-platform
feat: remove deprecated coaching from edx-platform
This commit is contained in:
@@ -19121,10 +19121,6 @@ msgid ""
|
||||
"subjects."
|
||||
msgstr "עיין בקורסים שהושקו לאחרונה וראה מה חדש בנושאים האהובים עליך."
|
||||
|
||||
#: themes/edx.org/lms/templates/dashboard.html
|
||||
msgid "Take advantage of free coaching!"
|
||||
msgstr ""
|
||||
|
||||
#: themes/edx.org/lms/templates/dashboard.html
|
||||
msgid "Get Started"
|
||||
msgstr ""
|
||||
|
||||
@@ -18201,10 +18201,6 @@ msgid ""
|
||||
"subjects."
|
||||
msgstr ""
|
||||
|
||||
#: themes/edx.org/lms/templates/dashboard.html
|
||||
msgid "Take advantage of free coaching!"
|
||||
msgstr ""
|
||||
|
||||
#: themes/edx.org/lms/templates/dashboard.html
|
||||
msgid "Get Started"
|
||||
msgstr ""
|
||||
|
||||
@@ -17370,10 +17370,6 @@ msgid ""
|
||||
"subjects."
|
||||
msgstr ""
|
||||
|
||||
#: themes/edx.org/lms/templates/dashboard.html
|
||||
msgid "Take advantage of free coaching!"
|
||||
msgstr ""
|
||||
|
||||
#: themes/edx.org/lms/templates/dashboard.html
|
||||
msgid "Get Started"
|
||||
msgstr ""
|
||||
|
||||
@@ -19492,10 +19492,6 @@ msgid ""
|
||||
"subjects."
|
||||
msgstr ""
|
||||
|
||||
#: themes/edx.org/lms/templates/dashboard.html
|
||||
msgid "Take advantage of free coaching!"
|
||||
msgstr ""
|
||||
|
||||
#: themes/edx.org/lms/templates/dashboard.html
|
||||
msgid "Get Started"
|
||||
msgstr ""
|
||||
|
||||
@@ -20296,10 +20296,6 @@ msgstr ""
|
||||
"Ознакомьтесь с недавно запущенными курсами и новостями по вашим любимым "
|
||||
"предметам."
|
||||
|
||||
#: themes/edx.org/lms/templates/dashboard.html
|
||||
msgid "Take advantage of free coaching!"
|
||||
msgstr ""
|
||||
|
||||
#: themes/edx.org/lms/templates/dashboard.html
|
||||
msgid "Get Started"
|
||||
msgstr ""
|
||||
|
||||
@@ -236,7 +236,6 @@ class ProgramTypeFactory(DictFactoryBase):
|
||||
class ProgramTypeAttrsFactory(DictFactoryBase):
|
||||
uuid = factory.Faker('uuid4')
|
||||
slug = factory.Faker('word')
|
||||
coaching_supported = False
|
||||
|
||||
|
||||
class ProgramFactory(DictFactoryBase):
|
||||
|
||||
@@ -11,6 +11,3 @@ class ExternalUserIDConfig(AppConfig):
|
||||
Default configuration for the "openedx.core.djangoapps.credit" Django application.
|
||||
"""
|
||||
name = 'openedx.core.djangoapps.external_user_ids'
|
||||
|
||||
def ready(self):
|
||||
from . import signals # pylint: disable=unused-import
|
||||
|
||||
@@ -20,7 +20,7 @@ class ExternalIdType(TimeStampedModel):
|
||||
|
||||
.. no_pii:
|
||||
"""
|
||||
MICROBACHELORS_COACHING = 'mb_coaching'
|
||||
|
||||
CALIPER = 'caliper'
|
||||
XAPI = 'xapi'
|
||||
LTI = 'lti'
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
"""
|
||||
Signal Handlers for External User Ids to be created and maintainer
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from openedx.core.djangoapps.catalog.utils import get_programs
|
||||
|
||||
from .models import ExternalId, ExternalIdType
|
||||
|
||||
LOGGER = getLogger(__name__)
|
||||
|
||||
|
||||
def _user_needs_external_id(instance, created):
|
||||
return (
|
||||
created and
|
||||
instance.user and
|
||||
not ExternalId.user_has_external_id(
|
||||
user=instance.user,
|
||||
type_name=ExternalIdType.MICROBACHELORS_COACHING)
|
||||
)
|
||||
|
||||
|
||||
@receiver(post_save, sender='student.CourseEnrollment')
|
||||
def create_external_id_for_microbachelors_program(
|
||||
sender, instance, created, **kwargs # pylint: disable=unused-argument
|
||||
):
|
||||
"""
|
||||
Watches for post_save signal for creates on the CourseEnrollment table.
|
||||
Generate an External ID if the Enrollment is in a MicroBachelors Program
|
||||
"""
|
||||
if _user_needs_external_id(instance, created):
|
||||
mb_programs = [
|
||||
program for program in get_programs(course=instance.course_id)
|
||||
if program.get('type_attrs', {}).get('coaching_supported')
|
||||
]
|
||||
if mb_programs:
|
||||
ExternalId.add_new_user_id(
|
||||
user=instance.user,
|
||||
type_name=ExternalIdType.MICROBACHELORS_COACHING
|
||||
)
|
||||
|
||||
|
||||
@receiver(post_save, sender='entitlements.CourseEntitlement')
|
||||
def create_external_id_for_microbachelors_program_entitlement(
|
||||
sender, instance, created, **kwargs # pylint: disable=unused-argument
|
||||
):
|
||||
"""
|
||||
Watches for post_save signal for creates on the CourseEntitlement table.
|
||||
Generate an External ID if the Entitlement is in a MicroBachelors Program
|
||||
"""
|
||||
if _user_needs_external_id(instance, created):
|
||||
mb_programs = [
|
||||
program for program in get_programs(catalog_course_uuid=instance.course_uuid)
|
||||
if program.get('type_attrs', {}).get('coaching_supported')
|
||||
]
|
||||
if mb_programs:
|
||||
ExternalId.add_new_user_id(
|
||||
user=instance.user,
|
||||
type_name=ExternalIdType.MICROBACHELORS_COACHING
|
||||
)
|
||||
@@ -14,7 +14,7 @@ class ExternalIDTypeFactory(factory.django.DjangoModelFactory): # lint-amnesty,
|
||||
class Meta:
|
||||
model = ExternalIdType
|
||||
|
||||
name = FuzzyChoice([ExternalIdType.MICROBACHELORS_COACHING])
|
||||
name = FuzzyChoice([ExternalIdType.CALIPER])
|
||||
description = FuzzyText()
|
||||
|
||||
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
"""
|
||||
Signal Tests for External User Ids that are sent out of Open edX
|
||||
"""
|
||||
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from django.core.cache import cache
|
||||
from edx_django_utils.cache import RequestCache
|
||||
|
||||
from common.djangoapps.entitlements.models import CourseEntitlement
|
||||
from openedx.core.djangoapps.catalog.tests.factories import (
|
||||
CourseFactory,
|
||||
ProgramFactory,
|
||||
)
|
||||
from common.djangoapps.student.tests.factories import TEST_PASSWORD, UserFactory, CourseEnrollmentFactory
|
||||
from openedx.core.djangoapps.catalog.cache import (
|
||||
CATALOG_COURSE_PROGRAMS_CACHE_KEY_TPL,
|
||||
COURSE_PROGRAMS_CACHE_KEY_TPL,
|
||||
PROGRAM_CACHE_KEY_TPL,
|
||||
)
|
||||
from openedx.core.djangoapps.external_user_ids.models import ExternalId, ExternalIdType
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
|
||||
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
|
||||
|
||||
|
||||
class MicrobachelorsExternalIDTest(ModuleStoreTestCase, CacheIsolationTestCase):
|
||||
"""
|
||||
Test cases for Signals for External User Ids
|
||||
"""
|
||||
ENABLED_CACHES = ['default']
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
cls.course_list = []
|
||||
cls.user = UserFactory.create()
|
||||
cls.course_keys = [
|
||||
CourseKey.from_string('course-v1:edX+DemoX+Test_Course'),
|
||||
CourseKey.from_string('course-v1:edX+DemoX+Another_Test_Course'),
|
||||
]
|
||||
ExternalIdType.objects.create(
|
||||
name=ExternalIdType.MICROBACHELORS_COACHING,
|
||||
description='test'
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
RequestCache.clear_all_namespaces()
|
||||
self.program = self._create_cached_program()
|
||||
self.client.login(username=self.user.username, password=TEST_PASSWORD)
|
||||
|
||||
def _create_cached_program(self):
|
||||
""" helper method to create a cached program """
|
||||
program = ProgramFactory.create()
|
||||
|
||||
for course_key in self.course_keys:
|
||||
program['courses'].append(CourseFactory(id=course_key))
|
||||
|
||||
program['type'] = 'MicroBachelors'
|
||||
program['type_attrs']['coaching_supported'] = True
|
||||
|
||||
for course in program['courses']:
|
||||
cache.set(
|
||||
CATALOG_COURSE_PROGRAMS_CACHE_KEY_TPL.format(course_uuid=course['uuid']),
|
||||
[program['uuid']],
|
||||
None
|
||||
)
|
||||
|
||||
course_run = course['course_runs'][0]['key']
|
||||
cache.set(
|
||||
COURSE_PROGRAMS_CACHE_KEY_TPL.format(course_run_id=course_run),
|
||||
[program['uuid']],
|
||||
None
|
||||
)
|
||||
cache.set(
|
||||
PROGRAM_CACHE_KEY_TPL.format(uuid=program['uuid']),
|
||||
program,
|
||||
None
|
||||
)
|
||||
|
||||
return program
|
||||
|
||||
def test_enroll_mb_create_external_id(self):
|
||||
course_run_key = self.program['courses'][0]['course_runs'][0]['key']
|
||||
|
||||
# Enroll user
|
||||
enrollment = CourseEnrollmentFactory.create(
|
||||
course_id=course_run_key,
|
||||
user=self.user,
|
||||
mode=CourseMode.VERIFIED,
|
||||
)
|
||||
enrollment.save()
|
||||
external_id = ExternalId.objects.get(
|
||||
user=self.user
|
||||
)
|
||||
assert external_id is not None
|
||||
assert external_id.external_id_type.name == ExternalIdType.MICROBACHELORS_COACHING
|
||||
|
||||
def test_second_enroll_mb_no_new_external_id(self):
|
||||
course_run_key1 = self.program['courses'][0]['course_runs'][0]['key']
|
||||
course_run_key2 = self.program['courses'][1]['course_runs'][0]['key']
|
||||
|
||||
# Enroll user
|
||||
CourseEnrollmentFactory.create(
|
||||
course_id=course_run_key1,
|
||||
user=self.user,
|
||||
mode=CourseMode.VERIFIED,
|
||||
)
|
||||
external_id = ExternalId.objects.get(
|
||||
user=self.user
|
||||
)
|
||||
assert external_id is not None
|
||||
assert external_id.external_id_type.name == ExternalIdType.MICROBACHELORS_COACHING
|
||||
original_external_user_uuid = external_id.external_user_id
|
||||
|
||||
CourseEnrollmentFactory.create(
|
||||
course_id=course_run_key2,
|
||||
user=self.user,
|
||||
mode=CourseMode.VERIFIED,
|
||||
)
|
||||
enrollments = CourseEnrollment.objects.filter(user=self.user)
|
||||
|
||||
assert len(enrollments) == 2
|
||||
|
||||
external_ids = ExternalId.objects.filter(
|
||||
user=self.user
|
||||
)
|
||||
|
||||
assert len(external_ids) == 1
|
||||
assert external_ids[0].external_id_type.name == ExternalIdType.MICROBACHELORS_COACHING
|
||||
assert original_external_user_uuid == external_ids[0].external_user_id
|
||||
|
||||
def test_entitlement_mb_create_external_id(self):
|
||||
catalog_course = self.program['courses'][0]
|
||||
|
||||
assert ExternalId.objects.filter(
|
||||
user=self.user
|
||||
).count() == 0
|
||||
|
||||
entitlement = CourseEntitlement.objects.create(
|
||||
course_uuid=catalog_course['uuid'],
|
||||
mode=CourseMode.VERIFIED,
|
||||
user=self.user,
|
||||
order_number='TEST-12345'
|
||||
)
|
||||
entitlement.save()
|
||||
|
||||
external_id = ExternalId.objects.get(
|
||||
user=self.user
|
||||
)
|
||||
assert external_id is not None
|
||||
assert external_id.external_id_type.name == ExternalIdType.MICROBACHELORS_COACHING
|
||||
|
||||
def test_second_entitlement_mb_no_new_external_id(self):
|
||||
catalog_course1 = self.program['courses'][0]
|
||||
catalog_course2 = self.program['courses'][1]
|
||||
|
||||
# Enroll user
|
||||
entitlement = CourseEntitlement.objects.create(
|
||||
course_uuid=catalog_course1['uuid'],
|
||||
mode=CourseMode.VERIFIED,
|
||||
user=self.user,
|
||||
order_number='TEST-12345'
|
||||
)
|
||||
entitlement.save()
|
||||
external_id = ExternalId.objects.get(
|
||||
user=self.user
|
||||
)
|
||||
assert external_id is not None
|
||||
assert external_id.external_id_type.name == ExternalIdType.MICROBACHELORS_COACHING
|
||||
original_external_user_uuid = external_id.external_user_id
|
||||
|
||||
CourseEntitlement.objects.create(
|
||||
course_uuid=catalog_course2['uuid'],
|
||||
mode=CourseMode.VERIFIED,
|
||||
user=self.user,
|
||||
order_number='TEST-12345'
|
||||
)
|
||||
entitlements = CourseEntitlement.objects.filter(user=self.user)
|
||||
|
||||
assert len(entitlements) == 2
|
||||
|
||||
external_ids = ExternalId.objects.filter(
|
||||
user=self.user
|
||||
)
|
||||
|
||||
assert len(external_ids) == 1
|
||||
assert external_ids[0].external_id_type.name == ExternalIdType.MICROBACHELORS_COACHING
|
||||
assert original_external_user_uuid == external_ids[0].external_user_id
|
||||
@@ -39,7 +39,7 @@ from openedx.core.djangoapps.credit.models import (
|
||||
CreditRequirement,
|
||||
CreditRequirementStatus
|
||||
)
|
||||
from openedx.core.djangoapps.external_user_ids.models import ExternalId, ExternalIdType
|
||||
from openedx.core.djangoapps.external_user_ids.models import ExternalIdType
|
||||
from openedx.core.djangoapps.oauth_dispatch.jwt import create_jwt_for_user
|
||||
from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory
|
||||
from openedx.core.djangoapps.user_api.accounts.views import AccountRetirementPartnerReportView
|
||||
@@ -496,7 +496,6 @@ class TestPartnerReportingList(ModuleStoreTestCase):
|
||||
"""
|
||||
EXPECTED_MB_ORGS_CONFIG = [
|
||||
{
|
||||
AccountRetirementPartnerReportView.ORGS_CONFIG_ORG_KEY: 'mb_coaching',
|
||||
AccountRetirementPartnerReportView.ORGS_CONFIG_FIELD_HEADINGS_KEY: [
|
||||
AccountRetirementPartnerReportView.STUDENT_ID_KEY,
|
||||
AccountRetirementPartnerReportView.ORIGINAL_EMAIL_KEY,
|
||||
@@ -516,7 +515,7 @@ class TestPartnerReportingList(ModuleStoreTestCase):
|
||||
self.url = reverse('accounts_retirement_partner_report')
|
||||
self.maxDiff = None
|
||||
self.test_created_datetime = datetime.datetime(2018, 1, 1, tzinfo=pytz.UTC)
|
||||
ExternalIdType.objects.get_or_create(name=ExternalIdType.MICROBACHELORS_COACHING)
|
||||
ExternalIdType.objects.get_or_create(name=ExternalIdType.CALIPER)
|
||||
|
||||
def get_user_dict(self, user, enrollments):
|
||||
"""
|
||||
@@ -624,56 +623,6 @@ class TestPartnerReportingList(ModuleStoreTestCase):
|
||||
|
||||
self.assert_status_and_user_list(user_dicts)
|
||||
|
||||
def test_success_mb_coaching(self):
|
||||
"""
|
||||
Check that MicroBachelors users who have consented to coaching have the proper info
|
||||
included for the partner report.
|
||||
"""
|
||||
path = 'openedx.core.djangoapps.user_api.accounts.views.has_ever_consented_to_coaching'
|
||||
with mock.patch(path, return_value=True) as mock_has_ever_consented:
|
||||
user_dicts, users = self.create_partner_reporting_statuses(num=1)
|
||||
external_id, created = ExternalId.add_new_user_id( # lint-amnesty, pylint: disable=unused-variable
|
||||
user=users[0],
|
||||
type_name=ExternalIdType.MICROBACHELORS_COACHING
|
||||
)
|
||||
|
||||
expected_user = user_dicts[0]
|
||||
expected_users = [expected_user]
|
||||
expected_user[AccountRetirementPartnerReportView.STUDENT_ID_KEY] = str(external_id.external_user_id)
|
||||
expected_user[
|
||||
AccountRetirementPartnerReportView.ORGS_CONFIG_KEY] = TestPartnerReportingList.EXPECTED_MB_ORGS_CONFIG
|
||||
|
||||
self.assert_status_and_user_list(expected_users)
|
||||
mock_has_ever_consented.assert_called_once()
|
||||
|
||||
def test_success_mb_coaching_no_external_id(self):
|
||||
"""
|
||||
Check that MicroBachelors users who have consented to coaching, but who do not have an external id, have the
|
||||
proper info included for the partner report.
|
||||
"""
|
||||
path = 'openedx.core.djangoapps.user_api.accounts.views.has_ever_consented_to_coaching'
|
||||
with mock.patch(path, return_value=True) as mock_has_ever_consented:
|
||||
user_dicts, users = self.create_partner_reporting_statuses(num=1) # lint-amnesty, pylint: disable=unused-variable
|
||||
|
||||
self.assert_status_and_user_list(user_dicts)
|
||||
mock_has_ever_consented.assert_called_once()
|
||||
|
||||
def test_success_mb_coaching_no_consent(self):
|
||||
"""
|
||||
Check that MicroBachelors users who have not consented to coaching have the proper info
|
||||
included for the partner report.
|
||||
"""
|
||||
path = 'openedx.core.djangoapps.user_api.accounts.views.has_ever_consented_to_coaching'
|
||||
with mock.patch(path, return_value=False) as mock_has_ever_consented:
|
||||
user_dicts, users = self.create_partner_reporting_statuses(num=1)
|
||||
ExternalId.add_new_user_id(
|
||||
user=users[0],
|
||||
type_name=ExternalIdType.MICROBACHELORS_COACHING
|
||||
)
|
||||
|
||||
self.assert_status_and_user_list(user_dicts)
|
||||
mock_has_ever_consented.assert_called_once()
|
||||
|
||||
def test_no_users(self):
|
||||
"""
|
||||
Checks that the call returns a success code and empty list if no users are found.
|
||||
|
||||
@@ -57,7 +57,6 @@ from openedx.core.djangoapps.ace_common.template_context import get_base_templat
|
||||
from openedx.core.djangoapps.api_admin.models import ApiAccessRequest
|
||||
from openedx.core.djangoapps.course_groups.models import UnregisteredLearnerCohortAssignments
|
||||
from openedx.core.djangoapps.credit.models import CreditRequest, CreditRequirementStatus
|
||||
from openedx.core.djangoapps.external_user_ids.models import ExternalId, ExternalIdType
|
||||
from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY
|
||||
from openedx.core.djangoapps.profile_images.images import remove_profile_images
|
||||
from openedx.core.djangoapps.user_api import accounts
|
||||
@@ -93,11 +92,6 @@ from .serializers import (
|
||||
from .signals import USER_RETIRE_LMS_CRITICAL, USER_RETIRE_LMS_MISC, USER_RETIRE_MAILINGS
|
||||
from .utils import create_retirement_request_and_deactivate_account, username_suffix_generator
|
||||
|
||||
try:
|
||||
from coaching.api import has_ever_consented_to_coaching
|
||||
except ImportError:
|
||||
has_ever_consented_to_coaching = None
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
USER_PROFILE_PII = {
|
||||
@@ -746,49 +740,8 @@ class AccountRetirementPartnerReportView(ViewSet):
|
||||
'created': retirement_status.created,
|
||||
}
|
||||
|
||||
# Some orgs have a custom list of headings and content for the partner report. Add this, if applicable.
|
||||
self._add_orgs_config_for_user(retirement, retirement_status.user)
|
||||
|
||||
return retirement
|
||||
|
||||
def _add_orgs_config_for_user(self, retirement, user):
|
||||
"""
|
||||
Check to see if the user's info was sent to any partners (orgs) that have a a custom list of headings and
|
||||
content for the partner report. If so, add this.
|
||||
"""
|
||||
# See if the MicroBachelors coaching provider needs to be notified of this user's retirement
|
||||
if has_ever_consented_to_coaching is not None and has_ever_consented_to_coaching(user):
|
||||
# See if the user has a MicroBachelors external id. If not, they were never sent to the
|
||||
# coaching provider.
|
||||
external_ids = ExternalId.objects.filter(
|
||||
user=user,
|
||||
external_id_type__name=ExternalIdType.MICROBACHELORS_COACHING
|
||||
)
|
||||
if external_ids.exists():
|
||||
# User has an external id. Add the additional info.
|
||||
external_id = str(external_ids[0].external_user_id)
|
||||
self._add_coaching_orgs_config(retirement, external_id)
|
||||
|
||||
def _add_coaching_orgs_config(self, retirement, external_id):
|
||||
"""
|
||||
Add the orgs configuration for MicroBachelors coaching
|
||||
"""
|
||||
# Add the custom field headings
|
||||
retirement[AccountRetirementPartnerReportView.ORGS_CONFIG_KEY] = [
|
||||
{
|
||||
AccountRetirementPartnerReportView.ORGS_CONFIG_ORG_KEY: 'mb_coaching',
|
||||
AccountRetirementPartnerReportView.ORGS_CONFIG_FIELD_HEADINGS_KEY: [
|
||||
AccountRetirementPartnerReportView.STUDENT_ID_KEY,
|
||||
AccountRetirementPartnerReportView.ORIGINAL_EMAIL_KEY,
|
||||
AccountRetirementPartnerReportView.ORIGINAL_NAME_KEY,
|
||||
AccountRetirementPartnerReportView.DELETION_COMPLETED_KEY
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
# Add the custom field value
|
||||
retirement[AccountRetirementPartnerReportView.STUDENT_ID_KEY] = external_id
|
||||
|
||||
@request_requires_username
|
||||
def retirement_partner_status_create(self, request):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user