Unverified Commit 3d884d6c by John Eskew Committed by GitHub

Merge pull request #16428 from edx/jeskew/email_mkting_lti_prov_to_appconfig_ready

Move lti_provider/email_marketing startup to AppConfig ready.
parents 333e1ccb 878d3eff
"""
Configuration for the edxmako Django application.
"""
from django.apps import AppConfig from django.apps import AppConfig
from django.conf import settings from django.conf import settings
from . import add_lookup, clear_lookups from . import add_lookup, clear_lookups
class EdxMakoConfig(AppConfig): class EdxMakoConfig(AppConfig):
"""
Configuration class for the edxmako Django application.
"""
name = 'edxmako' name = 'edxmako'
verbose_name = "edX Mako Templating" verbose_name = "edX Mako Templating"
......
"""
Configuration for the email_marketing Django application.
"""
from django.apps import AppConfig
class EmailMarketingConfig(AppConfig):
"""
Configuration class for the email_marketing Django application.
"""
name = 'email_marketing'
verbose_name = "Email Marketing"
def ready(self):
# Register the signal handlers.
from . import signals # pylint: disable=unused-import
""" email_marketing app. """
# this is here to support registering the signals in signals.py
from email_marketing import signals # pylint: disable=unused-import
"""
Configuration for the lti_provider Django application.
"""
from django.apps import AppConfig
class LtiProviderConfig(AppConfig):
"""
Configuration class for the lti_provider Django application.
"""
name = 'lti_provider'
verbose_name = "LTI Provider"
def ready(self):
# Import the tasks module to ensure that signal handlers are registered.
from . import signals # pylint: disable=unused-import
"""
Signals handlers for the lti_provider Django app.
"""
from __future__ import absolute_import
import logging
from django.conf import settings
from django.dispatch import receiver
import lti_provider.outcomes as outcomes
from lms.djangoapps.grades.signals.signals import PROBLEM_WEIGHTED_SCORE_CHANGED
from lti_provider.views import parse_course_and_usage_keys
from xmodule.modulestore.django import modulestore
from .tasks import send_composite_outcome, send_leaf_outcome
log = logging.getLogger(__name__)
def increment_assignment_versions(course_key, usage_key, user_id):
"""
Update the version numbers for all assignments that are affected by a score
change event. Returns a list of all affected assignments.
"""
problem_descriptor = modulestore().get_item(usage_key)
# Get all assignments involving the current problem for which the campus LMS
# is expecting a grade. There may be many possible graded assignments, if
# a problem has been added several times to a course at different
# granularities (such as the unit or the vertical).
assignments = outcomes.get_assignments_for_problem(
problem_descriptor, user_id, course_key
)
for assignment in assignments:
assignment.version_number += 1
assignment.save()
return assignments
@receiver(PROBLEM_WEIGHTED_SCORE_CHANGED)
def score_changed_handler(sender, **kwargs): # pylint: disable=unused-argument
"""
Consume signals that indicate score changes. See the definition of
PROBLEM_WEIGHTED_SCORE_CHANGED for a description of the signal.
"""
points_possible = kwargs.get('weighted_possible', None)
points_earned = kwargs.get('weighted_earned', None)
user_id = kwargs.get('user_id', None)
course_id = kwargs.get('course_id', None)
usage_id = kwargs.get('usage_id', None)
if None not in (points_earned, points_possible, user_id, course_id):
course_key, usage_key = parse_course_and_usage_keys(course_id, usage_id)
assignments = increment_assignment_versions(course_key, usage_key, user_id)
for assignment in assignments:
if assignment.usage_key == usage_key:
send_leaf_outcome.delay(
assignment.id, points_earned, points_possible
)
else:
send_composite_outcome.apply_async(
(user_id, course_id, assignment.id, assignment.version_number),
countdown=settings.LTI_AGGREGATE_SCORE_PASSBACK_DELAY
)
else:
log.error(
"Outcome Service: Required signal parameter is None. "
"points_possible: %s, points_earned: %s, user_id: %s, "
"course_id: %s, usage_id: %s",
points_possible, points_earned, user_id, course_id, usage_id
)
"""Code run at server start up to initialize the lti_provider app."""
# Import the tasks module to ensure that signal handlers are registered.
import lms.djangoapps.lti_provider.tasks # pylint: disable=unused-import
...@@ -4,73 +4,16 @@ Asynchronous tasks for the LTI provider app. ...@@ -4,73 +4,16 @@ Asynchronous tasks for the LTI provider app.
import logging import logging
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.dispatch import receiver
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
import lti_provider.outcomes as outcomes import lti_provider.outcomes as outcomes
from lms import CELERY_APP from lms import CELERY_APP
from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory
from lms.djangoapps.grades.signals.signals import PROBLEM_WEIGHTED_SCORE_CHANGED
from lti_provider.models import GradedAssignment from lti_provider.models import GradedAssignment
from lti_provider.views import parse_course_and_usage_keys
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
log = logging.getLogger("edx.lti_provider") log = logging.getLogger(__name__)
@receiver(PROBLEM_WEIGHTED_SCORE_CHANGED)
def score_changed_handler(sender, **kwargs): # pylint: disable=unused-argument
"""
Consume signals that indicate score changes. See the definition of
PROBLEM_WEIGHTED_SCORE_CHANGED for a description of the signal.
"""
points_possible = kwargs.get('weighted_possible', None)
points_earned = kwargs.get('weighted_earned', None)
user_id = kwargs.get('user_id', None)
course_id = kwargs.get('course_id', None)
usage_id = kwargs.get('usage_id', None)
if None not in (points_earned, points_possible, user_id, course_id):
course_key, usage_key = parse_course_and_usage_keys(course_id, usage_id)
assignments = increment_assignment_versions(course_key, usage_key, user_id)
for assignment in assignments:
if assignment.usage_key == usage_key:
send_leaf_outcome.delay(
assignment.id, points_earned, points_possible
)
else:
send_composite_outcome.apply_async(
(user_id, course_id, assignment.id, assignment.version_number),
countdown=settings.LTI_AGGREGATE_SCORE_PASSBACK_DELAY
)
else:
log.error(
"Outcome Service: Required signal parameter is None. "
"points_possible: %s, points_earned: %s, user_id: %s, "
"course_id: %s, usage_id: %s",
points_possible, points_earned, user_id, course_id, usage_id
)
def increment_assignment_versions(course_key, usage_key, user_id):
"""
Update the version numbers for all assignments that are affected by a score
change event. Returns a list of all affected assignments.
"""
problem_descriptor = modulestore().get_item(usage_key)
# Get all assignments involving the current problem for which the campus LMS
# is expecting a grade. There may be many possible graded assignments, if
# a problem has been added several times to a course at different
# granularities (such as the unit or the vertical).
assignments = outcomes.get_assignments_for_problem(
problem_descriptor, user_id, course_key
)
for assignment in assignments:
assignment.version_number += 1
assignment.save()
return assignments
@CELERY_APP.task(name='lti_provider.tasks.send_composite_outcome') @CELERY_APP.task(name='lti_provider.tasks.send_composite_outcome')
......
...@@ -869,7 +869,7 @@ CREDIT_PROVIDER_SECRET_KEYS = AUTH_TOKENS.get("CREDIT_PROVIDER_SECRET_KEYS", {}) ...@@ -869,7 +869,7 @@ CREDIT_PROVIDER_SECRET_KEYS = AUTH_TOKENS.get("CREDIT_PROVIDER_SECRET_KEYS", {})
##################### LTI Provider ##################### ##################### LTI Provider #####################
if FEATURES.get('ENABLE_LTI_PROVIDER'): if FEATURES.get('ENABLE_LTI_PROVIDER'):
INSTALLED_APPS.append('lti_provider') INSTALLED_APPS.append('lti_provider.apps.LtiProviderConfig')
AUTHENTICATION_BACKENDS.append('lti_provider.users.LtiBackend') AUTHENTICATION_BACKENDS.append('lti_provider.users.LtiBackend')
LTI_USER_EMAIL_DOMAIN = ENV_TOKENS.get('LTI_USER_EMAIL_DOMAIN', 'lti.example.com') LTI_USER_EMAIL_DOMAIN = ENV_TOKENS.get('LTI_USER_EMAIL_DOMAIN', 'lti.example.com')
......
...@@ -2289,7 +2289,7 @@ INSTALLED_APPS = [ ...@@ -2289,7 +2289,7 @@ INSTALLED_APPS = [
'django_sites_extensions', 'django_sites_extensions',
# Email marketing integration # Email marketing integration
'email_marketing', 'email_marketing.apps.EmailMarketingConfig',
# additional release utilities to ease automation # additional release utilities to ease automation
'release_util', 'release_util',
......
...@@ -571,7 +571,7 @@ PROFILE_IMAGE_MIN_BYTES = 100 ...@@ -571,7 +571,7 @@ PROFILE_IMAGE_MIN_BYTES = 100
# Enable the LTI provider feature for testing # Enable the LTI provider feature for testing
FEATURES['ENABLE_LTI_PROVIDER'] = True FEATURES['ENABLE_LTI_PROVIDER'] = True
INSTALLED_APPS.append('lti_provider') INSTALLED_APPS.append('lti_provider.apps.LtiProviderConfig')
AUTHENTICATION_BACKENDS.append('lti_provider.users.LtiBackend') AUTHENTICATION_BACKENDS.append('lti_provider.users.LtiBackend')
# ORGANIZATIONS # ORGANIZATIONS
......
...@@ -319,7 +319,7 @@ if FEATURES.get('INDIVIDUAL_DUE_DATES'): ...@@ -319,7 +319,7 @@ if FEATURES.get('INDIVIDUAL_DUE_DATES'):
##################### LTI Provider ##################### ##################### LTI Provider #####################
if FEATURES.get('ENABLE_LTI_PROVIDER'): if FEATURES.get('ENABLE_LTI_PROVIDER'):
INSTALLED_APPS.append('lti_provider') INSTALLED_APPS.append('lti_provider.apps.LtiProviderConfig')
AUTHENTICATION_BACKENDS.append('lti_provider.users.LtiBackend') AUTHENTICATION_BACKENDS.append('lti_provider.users.LtiBackend')
################################ Settings for Credentials Service ################################ ################################ Settings for Credentials Service ################################
......
...@@ -231,14 +231,7 @@ class TestUserPreferenceMiddleware(TestCase): ...@@ -231,14 +231,7 @@ class TestUserPreferenceMiddleware(TestCase):
# No preference yet, should write to the database # No preference yet, should write to the database
self.assertEqual(get_user_preference(self.user, LANGUAGE_KEY), None) self.assertEqual(get_user_preference(self.user, LANGUAGE_KEY), None)
self.middleware.process_request(self.request)
# The 'email_marketing' app is installed in the LMS env but not the CMS env. It listens for the
# USER_FIELD_CHANGED signal (utils.model_utils) and does a query to check the EmailMarketingConfiguration
# table to see if Sailthru integreation is enabled.
expected_queries = 6 if 'email_marketing' in settings.INSTALLED_APPS else 5
with self.assertNumQueries(expected_queries):
self.middleware.process_request(self.request)
self.assertEqual(get_user_preference(self.user, LANGUAGE_KEY), 'es') self.assertEqual(get_user_preference(self.user, LANGUAGE_KEY), 'es')
response = mock.Mock(spec=HttpResponse) response = mock.Mock(spec=HttpResponse)
...@@ -261,14 +254,7 @@ class TestUserPreferenceMiddleware(TestCase): ...@@ -261,14 +254,7 @@ class TestUserPreferenceMiddleware(TestCase):
# Cookie changed, should write to the database again # Cookie changed, should write to the database again
self.request.COOKIES[settings.LANGUAGE_COOKIE] = 'en' self.request.COOKIES[settings.LANGUAGE_COOKIE] = 'en'
self.middleware.process_request(self.request)
# The 'email_marketing' app is installed in the LMS env but not the CMS env. It listens for the
# USER_FIELD_CHANGED signal (utils.model_utils) and does a query to check the EmailMarketingConfiguration
# table to see if Sailthru integreation is enabled.
expected_queries = 6 if 'email_marketing' in settings.INSTALLED_APPS else 5
with self.assertNumQueries(expected_queries):
self.middleware.process_request(self.request)
self.assertEqual(get_user_preference(self.user, LANGUAGE_KEY), 'en') self.assertEqual(get_user_preference(self.user, LANGUAGE_KEY), 'en')
with self.assertNumQueries(1): with self.assertNumQueries(1):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment