From 12569b459f76765ab1f13163685c9dc6623ad983 Mon Sep 17 00:00:00 2001 From: Deborah Kaplan Date: Thu, 25 Jul 2024 15:06:24 -0400 Subject: [PATCH] feat: removing djangoapp `demographics`, step 1 (#35182) * feat: removing djangoapp `demographics`, step 1 This step removes the models, the references to the models, and adds a migration to drop both tables (`HistoricalUserDemographics` didn't have a corresponding model but was still a valid table). Once this has deployed, this will be removed from `INSTALLED_APPS` and completely removed. No other apps in the repository currently reference this djangoapp in code or tables. FIXES: APER-3560 --- openedx/core/djangoapps/demographics/admin.py | 19 ----- .../djangoapps/demographics/api/status.py | 13 +-- .../0005_remove_demographics_models.py | 23 ++++++ .../core/djangoapps/demographics/models.py | 27 ------- .../demographics/rest_api/v1/views.py | 30 ++----- .../djangoapps/demographics/tests/__init__.py | 0 .../demographics/tests/factories.py | 16 ---- .../demographics/tests/test_status.py | 81 ------------------- 8 files changed, 31 insertions(+), 178 deletions(-) create mode 100644 openedx/core/djangoapps/demographics/migrations/0005_remove_demographics_models.py delete mode 100644 openedx/core/djangoapps/demographics/tests/__init__.py delete mode 100644 openedx/core/djangoapps/demographics/tests/factories.py delete mode 100644 openedx/core/djangoapps/demographics/tests/test_status.py diff --git a/openedx/core/djangoapps/demographics/admin.py b/openedx/core/djangoapps/demographics/admin.py index 115581a7fb5f..7ae952ee1dbf 100644 --- a/openedx/core/djangoapps/demographics/admin.py +++ b/openedx/core/djangoapps/demographics/admin.py @@ -1,22 +1,3 @@ """ Django admin page for demographics """ - -from django.contrib import admin - -from openedx.core.djangoapps.demographics.models import UserDemographics - - -class UserDemographicsAdmin(admin.ModelAdmin): - """ - Admin for UserDemographics Model - """ - list_display = ('id', 'user', 'show_call_to_action') - readonly_fields = ('user',) - search_fields = ('id', 'user__username') - - class Meta: - model = UserDemographics - - -admin.site.register(UserDemographics, UserDemographicsAdmin) diff --git a/openedx/core/djangoapps/demographics/api/status.py b/openedx/core/djangoapps/demographics/api/status.py index cb861cf92f81..5dfb1e8f1942 100644 --- a/openedx/core/djangoapps/demographics/api/status.py +++ b/openedx/core/djangoapps/demographics/api/status.py @@ -2,9 +2,8 @@ Python API for Demographics Status """ -from openedx.features.enterprise_support.utils import is_enterprise_learner from openedx.core.djangoapps.programs.api import is_user_enrolled_in_program_type -from openedx.core.djangoapps.demographics.models import UserDemographics +from openedx.features.enterprise_support.utils import is_enterprise_learner def show_user_demographics(user, enrollments=None, entitlements=None): @@ -13,10 +12,7 @@ def show_user_demographics(user, enrollments=None, entitlements=None): to MicroBachlors Programs' learners who aren't part of an enterprise. """ is_user_in_microbachelors_program = is_user_enrolled_in_program_type( - user, - "microbachelors", - enrollments=enrollments, - entitlements=entitlements + user, "microbachelors", enrollments=enrollments, entitlements=entitlements ) return is_user_in_microbachelors_program and not is_enterprise_learner(user) @@ -26,7 +22,4 @@ def show_call_to_action_for_user(user): Utility method to determine if a user should be shown the Demographics call to action. """ - try: - return UserDemographics.objects.get(user=user).show_call_to_action - except UserDemographics.DoesNotExist: - return True + return False diff --git a/openedx/core/djangoapps/demographics/migrations/0005_remove_demographics_models.py b/openedx/core/djangoapps/demographics/migrations/0005_remove_demographics_models.py new file mode 100644 index 000000000000..aa33188d6269 --- /dev/null +++ b/openedx/core/djangoapps/demographics/migrations/0005_remove_demographics_models.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.14 on 2024-07-25 15:19 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('demographics', '0004_alter_historicaluserdemographics_options'), + ] + + operations = [ + migrations.RemoveField( + model_name='userdemographics', + name='user', + ), + migrations.DeleteModel( + name='HistoricalUserDemographics', + ), + migrations.DeleteModel( + name='UserDemographics', + ), + ] diff --git a/openedx/core/djangoapps/demographics/models.py b/openedx/core/djangoapps/demographics/models.py index 09c9251b0e40..be66352f64bd 100644 --- a/openedx/core/djangoapps/demographics/models.py +++ b/openedx/core/djangoapps/demographics/models.py @@ -1,30 +1,3 @@ """ Demographics models """ - -from django.contrib.auth import get_user_model -from django.db import models -from model_utils.models import TimeStampedModel -from simple_history.models import HistoricalRecords - -User = get_user_model() - - -class UserDemographics(TimeStampedModel): - """ - A Users Demographics platform related data in support of the Demographics - IDA and features - - .. no_pii: - """ - user = models.OneToOneField(User, on_delete=models.CASCADE) - show_call_to_action = models.BooleanField(default=True) - history = HistoricalRecords(app='demographics') - - class Meta: - app_label = "demographics" - verbose_name = "user demographic" - verbose_name_plural = "user demographic" - - def __str__(self): - return f'UserDemographics for {self.user}' diff --git a/openedx/core/djangoapps/demographics/rest_api/v1/views.py b/openedx/core/djangoapps/demographics/rest_api/v1/views.py index 35aacc61bd24..04c06ccdcd8b 100644 --- a/openedx/core/djangoapps/demographics/rest_api/v1/views.py +++ b/openedx/core/djangoapps/demographics/rest_api/v1/views.py @@ -1,12 +1,9 @@ # lint-amnesty, pylint: disable=missing-module-docstring -from rest_framework import permissions, status +from rest_framework import permissions from rest_framework.response import Response from rest_framework.views import APIView -from openedx.core.djangoapps.demographics.api.status import ( - show_user_demographics, show_call_to_action_for_user, -) -from openedx.core.djangoapps.demographics.models import UserDemographics +from openedx.core.djangoapps.demographics.api.status import show_call_to_action_for_user, show_user_demographics class DemographicsStatusView(APIView): @@ -16,7 +13,8 @@ class DemographicsStatusView(APIView): The API will return whether or not to display the Demographics UI based on the User's status in the Platform """ - permission_classes = (permissions.IsAuthenticated, ) + + permission_classes = (permissions.IsAuthenticated,) def _response_context(self, user, user_demographics=None): """ @@ -26,10 +24,7 @@ def _response_context(self, user, user_demographics=None): show_call_to_action = user_demographics.show_call_to_action else: show_call_to_action = show_call_to_action_for_user(user) - return { - 'display': show_user_demographics(user), - 'show_call_to_action': show_call_to_action - } + return {"display": show_user_demographics(user), "show_call_to_action": show_call_to_action} def get(self, request): """ @@ -39,18 +34,3 @@ def get(self, request): """ user = request.user return Response(self._response_context(user)) - - def patch(self, request): - """ - PATCH /api/user/v1/accounts/demographics/status - - This is a Web API to update fields that are dependent on user interaction. - """ - show_call_to_action = request.data.get('show_call_to_action') - user = request.user - if not isinstance(show_call_to_action, bool): - return Response(status.HTTP_400_BAD_REQUEST) - (user_demographics, _) = UserDemographics.objects.get_or_create(user=user) - user_demographics.show_call_to_action = show_call_to_action - user_demographics.save() - return Response(self._response_context(user, user_demographics)) diff --git a/openedx/core/djangoapps/demographics/tests/__init__.py b/openedx/core/djangoapps/demographics/tests/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/openedx/core/djangoapps/demographics/tests/factories.py b/openedx/core/djangoapps/demographics/tests/factories.py deleted file mode 100644 index 9678eaec6d6a..000000000000 --- a/openedx/core/djangoapps/demographics/tests/factories.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -Factoryboy factories for Demographics. -""" - -import factory - -from openedx.core.djangoapps.demographics.models import UserDemographics - - -class UserDemographicsFactory(factory.django.DjangoModelFactory): - """ - UserDemographics Factory - """ - - class Meta: - model = UserDemographics diff --git a/openedx/core/djangoapps/demographics/tests/test_status.py b/openedx/core/djangoapps/demographics/tests/test_status.py deleted file mode 100644 index 525b82e13c8c..000000000000 --- a/openedx/core/djangoapps/demographics/tests/test_status.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Test status utilities -""" -from unittest import TestCase -from unittest import mock - -from django.conf import settings -from opaque_keys.edx.keys import CourseKey -from pytest import mark -from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase -from xmodule.modulestore.tests.factories import CourseFactory - -from common.djangoapps.course_modes.models import CourseMode -from common.djangoapps.course_modes.tests.factories import CourseModeFactory -from common.djangoapps.student.tests.factories import UserFactory -from openedx.core.djangoapps.catalog.tests.factories import ( - ProgramFactory, -) -from openedx.core.djangolib.testing.utils import skip_unless_lms -from openedx.features.enterprise_support.tests.factories import EnterpriseCustomerUserFactory - -if settings.ROOT_URLCONF == 'lms.urls': - from openedx.core.djangoapps.demographics.api.status import show_user_demographics, show_call_to_action_for_user - from openedx.core.djangoapps.demographics.tests.factories import UserDemographicsFactory - -MICROBACHELORS = 'microbachelors' - - -@skip_unless_lms -@mock.patch('openedx.core.djangoapps.programs.utils.get_programs_by_type') -class TestShowDemographics(SharedModuleStoreTestCase): - """ - Tests for whether the demographics collection fields should be shown - """ - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.store = modulestore() - cls.user = UserFactory() - cls.program = ProgramFactory(type=MICROBACHELORS) - cls.catalog_course_run = cls.program['courses'][0]['course_runs'][0] - cls.course_key = CourseKey.from_string(cls.catalog_course_run['key']) - cls.course_run = CourseFactory.create( - org=cls.course_key.org, - number=cls.course_key.course, - run=cls.course_key.run, - modulestore=cls.store, - ) - CourseModeFactory.create(course_id=cls.course_run.id, mode_slug=CourseMode.VERIFIED) - - def test_user_enterprise(self, mock_get_programs_by_type): - mock_get_programs_by_type.return_value = [self.program] - EnterpriseCustomerUserFactory.create(user_id=self.user.id) - assert not show_user_demographics(user=self.user) - - -@skip_unless_lms -@mark.django_db -class TestShowCallToAction(TestCase): - """ - Tests for whether the demographics call to action should be shown - """ - def setUp(self): - super().setUp() - self.user = UserFactory() - - def test_new_user(self): - assert show_call_to_action_for_user(self.user) - - def test_existing_user_no_dismiss(self): - user_demographics = UserDemographicsFactory.create(user=self.user) - assert user_demographics.show_call_to_action - assert show_call_to_action_for_user(self.user) - - def test_existing_user_dismissed(self): - user_demographics = UserDemographicsFactory.create(user=self.user) - user_demographics.show_call_to_action = False - user_demographics.save() - assert not user_demographics.show_call_to_action - assert not show_call_to_action_for_user(self.user)