Files
edx-platform/lms/djangoapps/program_enrollments/signals.py
Kyle McCormick 151bd13666 Use full names for common.djangoapps imports; warn when using old style (#25477)
* Generate common/djangoapps import shims for LMS
* Generate common/djangoapps import shims for Studio
* Stop appending project root to sys.path
* Stop appending common/djangoapps to sys.path
* Import from common.djangoapps.course_action_state instead of course_action_state
* Import from common.djangoapps.course_modes instead of course_modes
* Import from common.djangoapps.database_fixups instead of database_fixups
* Import from common.djangoapps.edxmako instead of edxmako
* Import from common.djangoapps.entitlements instead of entitlements
* Import from common.djangoapps.pipline_mako instead of pipeline_mako
* Import from common.djangoapps.static_replace instead of static_replace
* Import from common.djangoapps.student instead of student
* Import from common.djangoapps.terrain instead of terrain
* Import from common.djangoapps.third_party_auth instead of third_party_auth
* Import from common.djangoapps.track instead of track
* Import from common.djangoapps.util instead of util
* Import from common.djangoapps.xblock_django instead of xblock_django
* Add empty common/djangoapps/__init__.py to fix pytest collection
* Fix pylint formatting violations
* Exclude import_shims/ directory tree from linting
2020-11-10 07:02:01 -05:00

95 lines
3.3 KiB
Python

"""
Signal handlers for program enrollments
"""
import logging
from django.db.models.signals import post_save
from django.dispatch import receiver
from social_django.models import UserSocialAuth
from openedx.core.djangoapps.catalog.utils import get_programs
from openedx.core.djangoapps.user_api.accounts.signals import USER_RETIRE_LMS_MISC
from common.djangoapps.third_party_auth.models import SAMLProviderConfig
from .api import fetch_program_enrollments_by_student, link_program_enrollment_to_lms_user
from .models import ProgramEnrollment
logger = logging.getLogger(__name__)
@receiver(USER_RETIRE_LMS_MISC)
def _listen_for_lms_retire(sender, **kwargs): # pylint: disable=unused-argument
"""
Listener for the USER_RETIRE_LMS_MISC signal, does user retirement
"""
user = kwargs.get('user')
ProgramEnrollment.retire_user(user.id)
@receiver(post_save, sender=UserSocialAuth)
def listen_for_social_auth_creation(sender, instance, created, **kwargs):
"""
Post-save signal that will attempt to link a social auth entry with waiting enrollments
"""
try:
matriculate_learner(instance.user, instance.uid)
except Exception as e:
logger.warning(
'Unable to link waiting enrollments for user %s, social auth creation failed: %s',
instance.user.id,
e,
)
raise
def matriculate_learner(user, uid):
"""
Update any waiting program enrollments with a user,
and enroll the user in any waiting course enrollments.
In most cases this will just short-circuit. Enrollments will only be updated
for a SAML provider with a linked organization.
"""
try:
provider_slug, external_user_key = uid.split(':')
authorizing_org = SAMLProviderConfig.objects.current_set().get(slug=provider_slug).organization
if not authorizing_org:
return
except (AttributeError, ValueError):
logger.debug('Ignoring non-saml social auth entry for user=%s', user.id)
return
except SAMLProviderConfig.DoesNotExist:
logger.warning(
'Got incoming social auth for provider=%s but no such provider exists', provider_slug
)
return
except SAMLProviderConfig.MultipleObjectsReturned:
logger.warning(
'Unable to activate waiting enrollments for user=%s.'
' Multiple active SAML configurations found for slug=%s. Expected one.',
user.id,
provider_slug)
return
incomplete_enrollments = fetch_program_enrollments_by_student(
external_user_key=external_user_key,
waiting_only=True,
).prefetch_related('program_course_enrollments')
for enrollment in incomplete_enrollments:
try:
enrollment_org = get_programs(uuid=enrollment.program_uuid)['authoring_organizations'][0]
if enrollment_org['key'] != authorizing_org.short_name:
continue
except (KeyError, TypeError):
logger.warning(
'Failed to complete waiting enrollments for organization=%s.'
' No catalog programs with matching authoring_organization exist.',
authorizing_org.short_name
)
continue
link_program_enrollment_to_lms_user(enrollment, user)