diff --git a/README.rst b/README.rst index fdfcdf657..1b3177633 100644 --- a/README.rst +++ b/README.rst @@ -104,30 +104,6 @@ Compatibility Notes The following changes to the plugin settings are necessary. If the release you are looking for is not listed, then the accumulation of changes from previous releases is enough. -**Ironwood** - -.. code-block:: yaml - - EOX_CORE_USERS_BACKEND: "eox_core.edxapp_wrapper.backends.users_h_v1" - EOX_CORE_PRE_ENROLLMENT_BACKEND: "eox_core.edxapp_wrapper.backends.pre_enrollment_h_v1" - EOX_CORE_ENROLLMENT_BACKEND: "eox_core.edxapp_wrapper.backends.enrollment_h_v1" - -**Juniper** - -.. code-block:: yaml - - EOX_CORE_USERS_BACKEND: "eox_core.edxapp_wrapper.backends.users_j_v1" - EOX_CORE_PRE_ENROLLMENT_BACKEND: "eox_core.edxapp_wrapper.backends.pre_enrollment_h_v1" - EOX_CORE_ENROLLMENT_BACKEND: "eox_core.edxapp_wrapper.backends.enrollment_h_v1" - -**Koa** - -.. code-block:: yaml - - EOX_CORE_USERS_BACKEND: "eox_core.edxapp_wrapper.backends.users_l_v1" - EOX_CORE_PRE_ENROLLMENT_BACKEND: "eox_core.edxapp_wrapper.backends.pre_enrollment_l_v1" - EOX_CORE_ENROLLMENT_BACKEND: "eox_core.edxapp_wrapper.backends.enrollment_l_v1" - **Lilac** .. code-block:: yaml diff --git a/eox_core/edxapp_wrapper/backends/coursekey_h_v1.py b/eox_core/edxapp_wrapper/backends/coursekey_h_v1.py deleted file mode 100644 index 5758d8fca..000000000 --- a/eox_core/edxapp_wrapper/backends/coursekey_h_v1.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Backend for the CourseKey validations that works under the open-release/hawthorn.beta1 tag -""" -# pylint: disable=import-error, protected-access -from __future__ import absolute_import, unicode_literals - -from django.conf import settings -from opaque_keys import InvalidKeyError -from opaque_keys.edx.keys import CourseKey -from rest_framework.serializers import ValidationError - -try: - from openedx.core.djangoapps.site_configuration.helpers import get_all_orgs, get_current_site_orgs -except ImportError: - get_all_orgs, get_current_site_orgs = object, object # pylint: disable=invalid-name - - -def get_valid_course_key(course_id): - """ - Return the CourseKey if the course_id is valid - """ - try: - return CourseKey.from_string(course_id) - except InvalidKeyError: - raise ValidationError(f"Invalid course_id {course_id}") from InvalidKeyError - - -def validate_org(course_id): - """ - Validate the course organization against all possible orgs for the site - - To determine if the Org is valid we must look at 3 things - 1 Orgs in the current site - 2 Orgs in other sites - 3 flag EOX_CORE_USER_ENABLE_MULTI_TENANCY - """ - - if not settings.EOX_CORE_USER_ENABLE_MULTI_TENANCY: - return True - - course_key = get_valid_course_key(course_id) - current_site_orgs = get_current_site_orgs() or [] - - if not current_site_orgs: # pylint: disable=no-else-return - if course_key.org in get_all_orgs(): - return False - return True - else: - return course_key.org in current_site_orgs diff --git a/eox_core/edxapp_wrapper/backends/pre_enrollment_h_v1.py b/eox_core/edxapp_wrapper/backends/pre_enrollment_h_v1.py deleted file mode 100644 index a23cb8125..000000000 --- a/eox_core/edxapp_wrapper/backends/pre_enrollment_h_v1.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Backend for the pre-enrollment (white listings) functionality that works under the open-release/hawthorn.beta1 tag -""" -# pylint: disable=import-error, protected-access -from __future__ import absolute_import, unicode_literals - -import logging - -from django.db import IntegrityError -from rest_framework.exceptions import NotFound -from student.models import CourseEnrollmentAllowed - -from eox_core.edxapp_wrapper.coursekey import get_valid_course_key -from eox_core.edxapp_wrapper.courseware import get_courseware_courses - -LOG = logging.getLogger(__name__) - - -def create_pre_enrollment(*args, **kwargs): - """ - Create pre-enrollment of given user in the course provided. - - Example: - >>>create_pre_enrollment( - { - "email": "bob@example.com", - "course_id": course-v1-edX-DemoX-1T2015", - "auto_enroll": "False" - } - ) - """ - warnings = [] - email = kwargs.get('email') - auto_enroll = kwargs.get('auto_enroll', False) - course_id = kwargs.pop('course_id') - - try: - course_key = get_valid_course_key(course_id) - pre_enrollment = CourseEnrollmentAllowed.objects.create(course_id=course_key, **kwargs) - # Check if the course exists otherwise add a warning - course = get_courseware_courses().get_course(course_key) - LOG.info('Creating regular pre-enrollment for email: %s course_id: %s auto_enroll: %s', email, course.id, auto_enroll) - except IntegrityError: - pre_enrollment = None - raise NotFound(f'Pre-enrollment already exists for email: {email} course_id: {course_id}') from IntegrityError - except ValueError: - warnings = [f'Course with course_id:{course_id} does not exist'] - return pre_enrollment, warnings - - -def update_pre_enrollment(*args, **kwargs): - """ - Update pre-enrollment of given user in the course provided. - - Example: - >>>update_pre_enrollment( - { - "email": "bob@example.com", - "course_id": course-v1-edX-DemoX-1T2015", - "auto_enroll": "False" - } - ) - """ - auto_enroll = kwargs.pop('auto_enroll', False) - pre_enrollment = kwargs.get('pre_enrollment') - try: - pre_enrollment.auto_enroll = auto_enroll - pre_enrollment.save() - LOG.info('Updating regular pre-enrollment for email: %s course_id: %s auto_enroll: %s', pre_enrollment.email, pre_enrollment.course_id, auto_enroll) - except Exception: # pylint: disable=broad-except - raise NotFound(f'Pre-enrollment not found for email: {pre_enrollment.email} course_id: {pre_enrollment.course_id}') from Exception - return pre_enrollment - - -def delete_pre_enrollment(*args, **kwargs): - """ - Delete pre-enrollment of given user in the course provided. - - Example: - >>>delete_pre_enrollment( - { - "email": "bob@example.com", - "course_id": course-v1-edX-DemoX-1T2015" - } - ) - """ - pre_enrollment = kwargs.get('pre_enrollment') - try: - LOG.info('Deleting regular pre-enrollment for email: %s course_id: %s', pre_enrollment.email, pre_enrollment.course_id) - pre_enrollment.delete() - except Exception: # pylint: disable=broad-except - raise NotFound(f'Pre-enrollment not found for email: {pre_enrollment.email} course_id: {pre_enrollment.course_id}') from Exception - - -def get_pre_enrollment(*args, **kwargs): - """ - Get pre-enrollment of given user in the course provided. - - Example: - >>>get_pre_enrollment( - { - "email": "bob@example.com", - "course_id": course-v1-edX-DemoX-1T2015" - } - ) - """ - email = kwargs.get('email') - course_id = kwargs.pop('course_id') - try: - course_key = get_valid_course_key(course_id) - pre_enrollment = CourseEnrollmentAllowed.objects.get(course_id=course_key, email=email) - LOG.info('Getting regular pre-enrollment for email: %s course_id: %s', email, course_id) - except CourseEnrollmentAllowed.DoesNotExist: - raise NotFound(f'Pre-enrollment not found for email: {email} course_id: {course_id}') from CourseEnrollmentAllowed.DoesNotExist - return pre_enrollment diff --git a/eox_core/edxapp_wrapper/backends/third_party_auth_j_v1.py b/eox_core/edxapp_wrapper/backends/third_party_auth_j_v1.py deleted file mode 100644 index 85b6d5e1f..000000000 --- a/eox_core/edxapp_wrapper/backends/third_party_auth_j_v1.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Backend for the third party authentication exception middleware.""" - - -def get_tpa_exception_middleware(): - """Get the ExceptionMiddleware class.""" - try: - from third_party_auth.middleware import ExceptionMiddleware # pylint: disable=import-outside-toplevel - except ImportError: - from django.utils.deprecation import \ - MiddlewareMixin as ExceptionMiddleware # pylint: disable=import-outside-toplevel - return ExceptionMiddleware diff --git a/eox_core/edxapp_wrapper/backends/users_h_v1.py b/eox_core/edxapp_wrapper/backends/users_h_v1.py deleted file mode 100644 index 14c1f2c5c..000000000 --- a/eox_core/edxapp_wrapper/backends/users_h_v1.py +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Backend for the create_edxapp_user that works under the open-release/hawthorn.beta1 tag -""" -from __future__ import absolute_import, unicode_literals - -import logging - -from django.conf import settings -from django.contrib.auth import get_user_model -from django.db import transaction -from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY # pylint: disable=import-error -from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers # pylint: disable=import-error -from openedx.core.djangoapps.user_api.accounts import USERNAME_MAX_LENGTH # pylint: disable=import-error,unused-import -from openedx.core.djangoapps.user_api.accounts.api import check_account_exists # pylint: disable=import-error -from openedx.core.djangoapps.user_api.accounts.serializers import UserReadOnlySerializer # pylint: disable=import-error -from openedx.core.djangoapps.user_api.preferences import api as preferences_api # pylint: disable=import-error -from rest_framework.exceptions import NotFound -from student.forms import AccountCreationForm # pylint: disable=import-error -from student.helpers import create_or_set_user_attribute_created_on_site # pylint: disable=import-error -from student.helpers import do_create_account # pylint: disable=import-error; pylint: disable=import-error -from student.models import CourseEnrollment # pylint: disable=import-error; pylint: disable=import-error -from student.models import ( # pylint: disable=import-error - UserAttribute, - UserProfile, - UserSignupSource, - create_comments_service_user, -) - -LOG = logging.getLogger(__name__) -User = get_user_model() # pylint: disable=invalid-name - - -def get_user_read_only_serializer(): - """ - Great serializer that fits our needs - """ - return UserReadOnlySerializer - - -def check_edxapp_account_conflicts(email, username): - """ - Exposed function to check conflicts - """ - return check_account_exists(email=email, username=username) - - -def create_edxapp_user(*args, **kwargs): - """ - Creates a user on the open edx django site using calls to - functions defined in the edx-platform codebase - - Example call: - - data = { - 'email': "address@example.org", - 'username': "Username", - 'password': "P4ssW0rd", - 'fullname': "Full Name", - 'activate': True, - 'site': request.site, - 'language_preference': 'es-419', - } - user = create_edxapp_user(**data) - - """ - errors = [] - - email = kwargs.pop("email") - username = kwargs.pop("username") - conflicts = check_edxapp_account_conflicts(email=email, username=username) - if conflicts: - return None, [f"Fatal: account collition with the provided: {', '.join(conflicts)}"] - - data = { - 'username': username, - 'email': email, - 'password': kwargs.pop("password"), - 'name': kwargs.pop("fullname"), - } - # Go ahead and create the new user - with transaction.atomic(): - # In theory is possible to extend the registration form with a custom app - # An example form app for this can be found at http://github.com/open-craft/custom-form-app - # form = get_registration_extension_form(data=params) - # if not form: - form = AccountCreationForm( - data=data, - tos_required=False, - # TODO: we need to support the extra profile fields as defined in the django.settings - # extra_fields=extra_fields, - # extended_profile_fields=extended_profile_fields, - # enforce_password_policy=enforce_password_policy, - ) - (user, profile, registration) = do_create_account(form) # pylint: disable=unused-variable - - site = kwargs.pop("site", False) - if site: - create_or_set_user_attribute_created_on_site(user, site) - else: - errors.append("The user was not assigned to any site") - - try: - create_comments_service_user(user) - except Exception: # pylint: disable=broad-except - errors.append("No comments_service_user was created") - - # TODO: link account with third party auth - - lang_pref = kwargs.pop("language_preference", False) - if lang_pref: - try: - preferences_api.set_user_preference(user, LANGUAGE_KEY, lang_pref) - except Exception: # pylint: disable=broad-except - errors.append(f"Could not set lang preference '{lang_pref}' for user '{user.username}'") - - if kwargs.pop("activate_user", False): - user.is_active = True - user.save() - - # TODO: run conditional email sequence - - return user, errors - - -def get_edxapp_user(**kwargs): - """ - Retrieve an user by username and/or email - - The user will be returned only if it belongs to the calling site - - Examples: - >>> get_edxapp_user( - { - "username": "Bob", - "site": request.site - } - ) - >>> get_edxapp_user( - { - "email": "Bob@mailserver.com", - "site": request.site - } - ) - """ - params = {key: kwargs.get(key) for key in ['username', 'email'] if key in kwargs} - site = kwargs.get('site') - try: - domain = site.domain - except AttributeError: - domain = None - - try: - user = User.objects.get(**params) - for source_method in FetchUserSiteSources.get_enabled_source_methods(): - if source_method(user, domain): - break - else: - raise User.DoesNotExist - except User.DoesNotExist: - raise NotFound(f'No user found by {str(params)} on site {domain}.') from User.DoesNotExist - return user - - -def get_course_team_user(*args, **kwargs): - """ - Get _course_team_user function. - We need to check if the SERVICE_VARIANT is equal to cms, since - contentstore is a module registered in the INSTALLED_APPS - of the cms only. - """ - if settings.SERVICE_VARIANT == 'cms': - from contentstore.views.user import _course_team_user # pylint: disable=import-error,import-outside-toplevel - return _course_team_user(*args, **kwargs) - return None - - -class FetchUserSiteSources: - """ - Methods to make the comparison to check if an user belongs to a site plus the - get_enabled_source_methods that just brings an array of functions enabled to do so - """ - - @classmethod - def get_enabled_source_methods(cls): - """ Brings the array of methods to check if an user belongs to a site. """ - sources = configuration_helpers.get_value( - 'EOX_CORE_USER_ORIGIN_SITE_SOURCES', - getattr(settings, 'EOX_CORE_USER_ORIGIN_SITE_SOURCES') - ) - return [getattr(cls, source) for source in sources] - - @staticmethod - def fetch_from_created_on_site_prop(user, domain): - """ Fetch option. """ - if not domain: - return False - return UserAttribute.get_user_attribute(user, 'created_on_site') == domain - - @staticmethod - def fetch_from_user_signup_source(user, domain): - """ Read the signup source. """ - return len(UserSignupSource.objects.filter(user=user, site=domain)) > 0 - - @staticmethod - def fetch_from_unfiltered_table(user, site): - """ Fetch option that does not take into account the multi-tentancy model of the installation. """ - return bool(user) - - -def get_course_enrollment(): - """ get CourseEnrollment model """ - return CourseEnrollment - - -def get_user_signup_source(): - """ get UserSignupSource model """ - return UserSignupSource - - -def get_user_profile(): - """ Gets the UserProfile model """ - - return UserProfile diff --git a/eox_core/edxapp_wrapper/backends/users_h_v1_test.py b/eox_core/edxapp_wrapper/backends/users_h_v1_test.py deleted file mode 100644 index 98c2698d7..000000000 --- a/eox_core/edxapp_wrapper/backends/users_h_v1_test.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -Test backend to get CourseEnrollment Model. -""" - -from django.contrib.auth.models import Permission - -USERNAME_MAX_LENGTH = 30 - - -def get_edxapp_user(**kwargs): - """ - Return a fake user - """ - return object - - -def create_edxapp_user(*args, **kwargs): - """ - Return a fake user and a list of errors - """ - return object, [] - - -def get_user_read_only_serializer(): - """ - Return a fake user read only serializer - """ - try: - from openedx.core.djangoapps.user_api.accounts.serializers import \ - UserReadOnlySerializer # pylint: disable=import-outside-toplevel - except ImportError: - UserReadOnlySerializer = object - return UserReadOnlySerializer - - -def check_edxapp_account_conflicts(email, username): - """ - Get an executes the check_account_exists for tests - """ - try: - from openedx.core.djangoapps.user_api.accounts.api import \ - check_account_exists # pylint: disable=import-outside-toplevel - except ImportError: - def check_account_exists(email=None, username=None): - """ - Fake definition for check_account_exists edxapp function - """ - return email and username - return check_account_exists(email=email, username=username) - - -def get_course_enrollment(): - """ - Get Test CourseEnrollment model. - - We return any django model that already exists so that - django-filters is happy and no migrations are created. - """ - return Permission - - -def get_course_team_user(*args, **kwargs): - """ - Return a fake course team user - """ - return object - - -def get_user_signup_source(): - """ - Get test UserSignupSource model - """ - try: - from student.models import UserSignupSource # pylint: disable=import-outside-toplevel - except ImportError: - UserSignupSource = object - return UserSignupSource - - -def get_user_profile(): - """ Gets the UserProfile model """ - try: - from student.models import UserProfile # pylint: disable=import-outside-toplevel - except ImportError: - UserProfile = object - return UserProfile - - -def generate_password(*args, **kwargs): - """ Generates a password """ - return "ThisShouldBeARandomPassword" - - -def get_user_attribute(): - """ - Get test UserAttribute model - """ - try: - from student.models import UserAttribute # pylint: disable=import-outside-toplevel - except ImportError: - UserAttribute = object - return UserAttribute diff --git a/eox_core/edxapp_wrapper/backends/users_j_v1.py b/eox_core/edxapp_wrapper/backends/users_j_v1.py deleted file mode 100644 index 1c43fde10..000000000 --- a/eox_core/edxapp_wrapper/backends/users_j_v1.py +++ /dev/null @@ -1,381 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Backend for the create_edxapp_user that works under the open-release/juniper.master tag -""" -from __future__ import absolute_import, unicode_literals - -import logging - -# pylint: disable=import-error -from crum import get_current_user -from django import forms -from django.conf import settings -from django.contrib.auth import get_user_model -from django.db import transaction -from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY -from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers -from openedx.core.djangoapps.user_api.accounts import USERNAME_MAX_LENGTH # pylint: disable=unused-import -from openedx.core.djangoapps.user_api.accounts.serializers import UserReadOnlySerializer -from openedx.core.djangoapps.user_api.accounts.views import _set_unusable_password # pylint: disable=unused-import -from openedx.core.djangoapps.user_api.models import UserRetirementStatus -from openedx.core.djangoapps.user_api.preferences import api as preferences_api -from openedx.core.djangoapps.user_authn.utils import generate_password # pylint: disable=unused-import -from openedx.core.djangoapps.user_authn.views.registration_form import AccountCreationForm -from openedx.core.djangolib.oauth2_retirement_utils import retire_dot_oauth2_models # pylint: disable=unused-import -from rest_framework import status -from rest_framework.exceptions import NotFound -from social_django.models import UserSocialAuth -from student.helpers import create_or_set_user_attribute_created_on_site, do_create_account -from student.models import ( - CourseEnrollment, - LoginFailures, - Registration, - UserAttribute, - UserProfile, - UserSignupSource, - create_comments_service_user, - email_exists_or_retired, - get_retired_email_by_email, - username_exists_or_retired, -) - -# pylint: disable=ungrouped-imports -try: - from openedx.core.lib.triggers.v1 import post_register -except ImportError: - # In case edx-platform -vanilla- Juniper release is used - from openedx.core.djangoapps.user_authn.views.register import REGISTER_USER as post_register - - -LOG = logging.getLogger(__name__) -User = get_user_model() # pylint: disable=invalid-name - - -def get_user_read_only_serializer(): - """ - Great serializer that fits our needs - """ - return UserReadOnlySerializer - - -def check_edxapp_account_conflicts(email, username): - """ - Exposed function to check conflicts - """ - conflicts = [] - - if username and username_exists_or_retired(username): - conflicts.append("username") - - if email and email_exists_or_retired(email): - conflicts.append("email") - - return conflicts - - -def is_allowed_to_skip_extra_registration_fields(account_creation_data): - """ - Returns True if the conditions are met to skip sending the extra - registrations fields durint the account creation. - - Three conditions are checked in order to be able to skip - these registration fields: - 1. The skip_extra_registration_fields field is sent in the data - for the account creation as True. - 2. The user making the request is staff. - 3. The data received in the parameters does not contain any of the - REGISTRATION_EXTRA_FIELDS configured for the microsite. - - In case any of these conditions is not met the function returns - False. - """ - skip_extra_registration_fields = account_creation_data.pop("skip_extra_registration_fields", False) - current_user = get_current_user() - extra_fields = getattr(settings, "REGISTRATION_EXTRA_FIELDS", {}) - extended_profile_fields = getattr(settings, "extended_profile_fields", []) - - if not (skip_extra_registration_fields and current_user.is_staff): - return False - - for field in account_creation_data.keys(): - if field in extra_fields.keys() or field in extended_profile_fields: - return False - - return True - - -class EdnxAccountCreationForm(AccountCreationForm): - """ - A form to extend the behaviour of the AccountCreationForm. - For now the purpose of this form is to allow to make the - password optional if the flag 'skip_password' is True. - - This form it's currently only used for validation, not rendering. - """ - - def __init__( # pylint:disable=too-many-arguments - self, - data=None, - extra_fields=None, - extended_profile_fields=None, - do_third_party_auth=True, - tos_required=True, - ): - super().__init__( - data=data, - extra_fields=extra_fields, - extended_profile_fields=extended_profile_fields, - do_third_party_auth=do_third_party_auth, - tos_required=tos_required, - ) - - if data.pop("skip_password", False): - self.fields['password'] = forms.CharField(required=False) - - -def create_edxapp_user(*args, **kwargs): - """ - Creates a user on the open edx django site using calls to - functions defined in the edx-platform codebase - - Example call: - - data = { - 'email': "address@example.org", - 'username': "Username", - 'password': "P4ssW0rd", - 'fullname': "Full Name", - 'activate': True, - 'site': request.site, - 'language_preference': 'es-419', - } - user = create_edxapp_user(**data) - - """ - errors = [] - - kwargs["name"] = kwargs.pop("fullname", None) - email = kwargs.get("email") - username = kwargs.get("username") - conflicts = check_edxapp_account_conflicts(email=email, username=username) - if conflicts: - return None, [f"Fatal: account collition with the provided: {', '.join(conflicts)}"] - - account_creation_form_data = { - "data": kwargs, - "tos_required": False, - # "enforce_password_policy": enforce_password_policy, - } - - # Check if we should send the extra registration fields - if not is_allowed_to_skip_extra_registration_fields(kwargs): - account_creation_form_data["extra_fields"] = getattr(settings, "REGISTRATION_EXTRA_FIELDS", {}) - account_creation_form_data["extended_profile_fields"] = getattr(settings, "extended_profile_fields", []) - - # Go ahead and create the new user - with transaction.atomic(): - # In theory is possible to extend the registration form with a custom app - # An example form app for this can be found at http://github.com/open-craft/custom-form-app - # form = get_registration_extension_form(data=params) - # if not form: - form = EdnxAccountCreationForm(**account_creation_form_data) - (user, profile, registration) = do_create_account(form) # pylint: disable=unused-variable - - site = kwargs.pop("site", False) - if site: - create_or_set_user_attribute_created_on_site(user, site) - else: - errors.append("The user was not assigned to any site") - - try: - create_comments_service_user(user) - except Exception: # pylint: disable=broad-except - errors.append("No comments_service_user was created") - - # TODO: link account with third party auth - - # Announce registration through API call - post_register.send_robust(sender=None, user=user) # pylint: disable=no-member - - lang_pref = kwargs.pop("language_preference", False) - if lang_pref: - try: - preferences_api.set_user_preference(user, LANGUAGE_KEY, lang_pref) - except Exception: # pylint: disable=broad-except - errors.append(f"Could not set lang preference '{lang_pref}' for user '{user.username}'") - - if kwargs.pop("activate_user", False): - user.is_active = True - user.save() - - # TODO: run conditional email sequence - - return user, errors - - -def get_edxapp_user(**kwargs): - """ - Retrieve a user by username and/or email - - The user will be returned only if it belongs to the calling site - - Examples: - >>> get_edxapp_user( - { - "username": "Bob", - "site": request.site - } - ) - >>> get_edxapp_user( - { - "email": "Bob@mailserver.com", - "site": request.site - } - ) - """ - params = {key: kwargs.get(key) for key in ['username', 'email'] if key in kwargs} - site = kwargs.get('site') - try: - domain = site.domain - except AttributeError: - domain = None - - try: - user = User.objects.get(**params) - for source_method in FetchUserSiteSources.get_enabled_source_methods(): - if source_method(user, domain): - break - else: - raise User.DoesNotExist - except User.DoesNotExist: - raise NotFound(f'No user found by {str(params)} on site {domain}.') from User.DoesNotExist - return user - - -def delete_edxapp_user(*args, **kwargs): - """ - Deletes a user from the platform. - """ - msg = None - - user = kwargs.get("user") - case_id = kwargs.get("case_id") - site = kwargs.get("site") - is_support_user = kwargs.get("is_support_user") - - user_response = f"The user {user.username} <{user.email}> " - - signup_sources = user.usersignupsource_set.all() - sources = [signup_source.site for signup_source in signup_sources] - - if site and site.name.upper() in (source.upper() for source in sources): - if len(sources) == 1: - with transaction.atomic(): - support_label = "_support" if is_support_user else "" - user.email = f"{user.email}{case_id}.ednx{support_label}_retired" - user.save() - - # Add user to retirement queue. - UserRetirementStatus.create_retirement(user) - - # Unlink LMS social auth accounts - UserSocialAuth.objects.filter(user_id=user.id).delete() - - # Change LMS password & email - user.email = get_retired_email_by_email(user.email) - user.save() - _set_unusable_password(user) - - # Remove the activation keys sent by email to the user for account activation. - Registration.objects.filter(user=user).delete() - - # Delete OAuth tokens associated with the user. - retire_dot_oauth2_models(user) - - # Delete user signup source object - signup_sources[0].delete() - - msg = f"{user_response} has been removed" - else: - for signup_source in signup_sources: - if signup_source.site.upper() == site.name.upper(): - signup_source.delete() - - msg = f"{user_response} has more than one signup source. The signup source from the site {site} has been deleted" - - return msg, status.HTTP_200_OK - - raise NotFound(f"{user_response} does not have a signup source on the site {site}") - - -def get_course_team_user(*args, **kwargs): - """ - Get _course_team_user function. - We need to check if the SERVICE_VARIANT is equal to cms, since - contentstore is a module registered in the INSTALLED_APPS - of the cms only. - """ - if settings.SERVICE_VARIANT == 'cms': - from contentstore.views.user import _course_team_user # pylint: disable=import-error,import-outside-toplevel - return _course_team_user(*args, **kwargs) - return None - - -class FetchUserSiteSources: - """ - Methods to make the comparison to check if an user belongs to a site plus the - get_enabled_source_methods that just brings an array of functions enabled to do so - """ - - @classmethod - def get_enabled_source_methods(cls): - """ Brings the array of methods to check if an user belongs to a site. """ - sources = configuration_helpers.get_value( - 'EOX_CORE_USER_ORIGIN_SITE_SOURCES', - getattr(settings, 'EOX_CORE_USER_ORIGIN_SITE_SOURCES') - ) - return [getattr(cls, source) for source in sources] - - @staticmethod - def fetch_from_created_on_site_prop(user, domain): - """ Fetch option. """ - if not domain: - return False - return UserAttribute.get_user_attribute(user, 'created_on_site') == domain - - @staticmethod - def fetch_from_user_signup_source(user, domain): - """ Read the signup source. """ - return len(UserSignupSource.objects.filter(user=user, site=domain)) > 0 - - @staticmethod - def fetch_from_unfiltered_table(user, site): - """ Fetch option that does not take into account the multi-tentancy model of the installation. """ - return bool(user) - - -def get_course_enrollment(): - """ get CourseEnrollment model """ - return CourseEnrollment - - -def get_user_signup_source(): - """ get UserSignupSource model """ - return UserSignupSource - - -def get_login_failures(): - """ get LoginFailures model """ - return LoginFailures - - -def get_user_profile(): - """ Gets the UserProfile model """ - - return UserProfile - - -def get_user_attribute(): - """ Gets the UserAttribute model """ - return UserAttribute diff --git a/eox_core/settings/test.py b/eox_core/settings/test.py index 0ffc9af5d..82b19801e 100644 --- a/eox_core/settings/test.py +++ b/eox_core/settings/test.py @@ -19,7 +19,7 @@ def plugin_settings(settings): # pylint: disable=function-redefined settings.EOX_CORE_USERS_BACKEND = "eox_core.edxapp_wrapper.backends.users_m_v1_test" settings.EOX_CORE_ENROLLMENT_BACKEND = "eox_core.edxapp_wrapper.backends.enrollment_l_v1" settings.EOX_CORE_PRE_ENROLLMENT_BACKEND = "eox_core.edxapp_wrapper.backends.pre_enrollment_l_v1" - settings.EOX_CORE_COURSEKEY_BACKEND = "eox_core.edxapp_wrapper.backends.coursekey_h_v1" + settings.EOX_CORE_COURSEKEY_BACKEND = "eox_core.edxapp_wrapper.backends.coursekey_m_v1" settings.EOX_CORE_CERTIFICATES_BACKEND = "eox_core.edxapp_wrapper.backends.certificates_h_v1_test" settings.EOX_CORE_CONFIGURATION_HELPER_BACKEND = "eox_core.edxapp_wrapper.backends.configuration_helpers_h_v1_test" settings.EOX_CORE_COURSEWARE_BACKEND = "eox_core.edxapp_wrapper.backends.courseware_h_v1"