@@ -916,7 +916,6 @@ INSTALLED_APPS = (
|
||||
# other apps that are. Django 1.8 wants to have imported models supported
|
||||
# by installed apps.
|
||||
'lms.djangoapps.verify_student',
|
||||
'lms.djangoapps.grades.apps.GradesConfig',
|
||||
|
||||
# Microsite configuration application
|
||||
'microsite_configuration',
|
||||
|
||||
@@ -360,6 +360,49 @@ class TestCreateAccount(TestCase):
|
||||
self.assertIsNone(UserAttribute.get_user_attribute(user, REGISTRATION_UTM_PARAMETERS.get('utm_content')))
|
||||
self.assertIsNone(UserAttribute.get_user_attribute(user, REGISTRATION_UTM_CREATED_AT))
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
def test_incomplete_utm_referral(self):
|
||||
"""Verify that no referral is recorded when a cookie is not present."""
|
||||
utm_cookie_name = 'edx.test.utm'
|
||||
with mock.patch('student.models.RegistrationCookieConfiguration.current') as config:
|
||||
instance = config.return_value
|
||||
instance.utm_cookie_name = utm_cookie_name
|
||||
|
||||
utm_cookie = {
|
||||
'utm_source': 'test-source',
|
||||
'utm_medium': 'test-medium',
|
||||
# No campaign
|
||||
'utm_term': 'test-term',
|
||||
'utm_content': 'test-content',
|
||||
# No created at
|
||||
}
|
||||
|
||||
self.client.cookies[utm_cookie_name] = json.dumps(utm_cookie)
|
||||
user = self.create_account_and_fetch_profile().user
|
||||
|
||||
self.assertEqual(
|
||||
UserAttribute.get_user_attribute(user, REGISTRATION_UTM_PARAMETERS.get('utm_source')),
|
||||
utm_cookie.get('utm_source')
|
||||
)
|
||||
self.assertEqual(
|
||||
UserAttribute.get_user_attribute(user, REGISTRATION_UTM_PARAMETERS.get('utm_medium')),
|
||||
utm_cookie.get('utm_medium')
|
||||
)
|
||||
self.assertEqual(
|
||||
UserAttribute.get_user_attribute(user, REGISTRATION_UTM_PARAMETERS.get('utm_term')),
|
||||
utm_cookie.get('utm_term')
|
||||
)
|
||||
self.assertEqual(
|
||||
UserAttribute.get_user_attribute(user, REGISTRATION_UTM_PARAMETERS.get('utm_content')),
|
||||
utm_cookie.get('utm_content')
|
||||
)
|
||||
self.assertIsNone(
|
||||
UserAttribute.get_user_attribute(user, REGISTRATION_UTM_PARAMETERS.get('utm_campaign'))
|
||||
)
|
||||
self.assertIsNone(
|
||||
UserAttribute.get_user_attribute(user, REGISTRATION_UTM_CREATED_AT)
|
||||
)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestCreateAccountValidation(TestCase):
|
||||
|
||||
@@ -1903,25 +1903,25 @@ def record_utm_registration_attribution(request, user):
|
||||
utm_cookie = request.COOKIES.get(utm_cookie_name)
|
||||
if user and utm_cookie:
|
||||
utm = json.loads(utm_cookie)
|
||||
for utm_parameter in REGISTRATION_UTM_PARAMETERS:
|
||||
UserAttribute.set_user_attribute(
|
||||
user,
|
||||
REGISTRATION_UTM_PARAMETERS.get(utm_parameter),
|
||||
utm.get(utm_parameter)
|
||||
)
|
||||
for utm_parameter_name in REGISTRATION_UTM_PARAMETERS:
|
||||
utm_parameter = utm.get(utm_parameter_name)
|
||||
if utm_parameter:
|
||||
UserAttribute.set_user_attribute(
|
||||
user,
|
||||
REGISTRATION_UTM_PARAMETERS.get(utm_parameter_name),
|
||||
utm_parameter
|
||||
)
|
||||
created_at_unixtime = utm.get('created_at')
|
||||
if created_at_unixtime:
|
||||
# We divide by 1000 here because the javascript timestamp generated is in milliseconds not seconds.
|
||||
# PYTHON: time.time() => 1475590280.823698
|
||||
# JS: new Date().getTime() => 1475590280823
|
||||
created_at_datetime = datetime.datetime.fromtimestamp(int(created_at_unixtime) / float(1000), tz=UTC)
|
||||
else:
|
||||
created_at_datetime = None
|
||||
UserAttribute.set_user_attribute(
|
||||
user,
|
||||
REGISTRATION_UTM_CREATED_AT,
|
||||
created_at_datetime
|
||||
)
|
||||
UserAttribute.set_user_attribute(
|
||||
user,
|
||||
REGISTRATION_UTM_CREATED_AT,
|
||||
created_at_datetime
|
||||
)
|
||||
|
||||
|
||||
def record_registration_attributions(request, user):
|
||||
|
||||
@@ -4,10 +4,11 @@ import logging
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import migrations
|
||||
from django.http import Http404
|
||||
|
||||
from ccx_keys.locator import CCXLocator
|
||||
from courseware.courses import get_course_by_id
|
||||
from instructor.access import allow_access, revoke_access
|
||||
from lms.djangoapps.ccx.utils import ccx_course
|
||||
|
||||
|
||||
log = logging.getLogger("edx.ccx")
|
||||
@@ -31,7 +32,11 @@ def change_existing_ccx_coaches_to_staff(apps, schema_editor):
|
||||
list_ccx = CustomCourseForEdX.objects.using(db_alias).all()
|
||||
for ccx in list_ccx:
|
||||
ccx_locator = CCXLocator.from_course_locator(ccx.course_id, unicode(ccx.id))
|
||||
with ccx_course(ccx_locator) as course:
|
||||
try:
|
||||
course = get_course_by_id(ccx_locator)
|
||||
except Http404:
|
||||
log.error('Could not migrate access for CCX course: %s', unicode(ccx_locator))
|
||||
else:
|
||||
coach = User.objects.get(id=ccx.coach.id)
|
||||
allow_access(course, coach, 'staff', send_email=False)
|
||||
revoke_access(course, coach, 'ccx_coach', send_email=False)
|
||||
@@ -57,7 +62,11 @@ def revert_ccx_staff_to_coaches(apps, schema_editor):
|
||||
list_ccx = CustomCourseForEdX.objects.using(db_alias).all()
|
||||
for ccx in list_ccx:
|
||||
ccx_locator = CCXLocator.from_course_locator(ccx.course_id, unicode(ccx.id))
|
||||
with ccx_course(ccx_locator) as course:
|
||||
try:
|
||||
course = get_course_by_id(ccx_locator)
|
||||
except Http404:
|
||||
log.error('Could not migrate access for CCX course: %s', unicode(ccx_locator))
|
||||
else:
|
||||
coach = User.objects.get(id=ccx.coach.id)
|
||||
allow_access(course, coach, 'ccx_coach', send_email=False)
|
||||
revoke_access(course, coach, 'staff', send_email=False)
|
||||
|
||||
@@ -70,7 +70,7 @@ def get_course_by_id(course_key, depth=0):
|
||||
if course:
|
||||
return course
|
||||
else:
|
||||
raise Http404("Course not found.")
|
||||
raise Http404("Course not found: {}.".format(unicode(course_key)))
|
||||
|
||||
|
||||
class UserNotEnrolled(Http404):
|
||||
|
||||
@@ -3,6 +3,7 @@ This module contains tasks for asynchronous execution of grade updates.
|
||||
"""
|
||||
|
||||
from celery import task
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from lms.djangoapps.course_blocks.api import get_course_blocks
|
||||
@@ -16,7 +17,7 @@ from .transformer import GradesTransformer
|
||||
from .new.subsection_grade import SubsectionGradeFactory
|
||||
|
||||
|
||||
@task()
|
||||
@task(routing_key=settings.RECALCULATE_GRADES_ROUTING_KEY)
|
||||
def recalculate_subsection_grade(user_id, course_id, usage_id):
|
||||
"""
|
||||
Updates a saved subsection grade.
|
||||
|
||||
@@ -259,7 +259,10 @@ BULK_EMAIL_DEFAULT_RETRY_DELAY = ENV_TOKENS.get('BULK_EMAIL_DEFAULT_RETRY_DELAY'
|
||||
BULK_EMAIL_MAX_RETRIES = ENV_TOKENS.get('BULK_EMAIL_MAX_RETRIES', BULK_EMAIL_MAX_RETRIES)
|
||||
BULK_EMAIL_INFINITE_RETRY_CAP = ENV_TOKENS.get('BULK_EMAIL_INFINITE_RETRY_CAP', BULK_EMAIL_INFINITE_RETRY_CAP)
|
||||
BULK_EMAIL_LOG_SENT_EMAILS = ENV_TOKENS.get('BULK_EMAIL_LOG_SENT_EMAILS', BULK_EMAIL_LOG_SENT_EMAILS)
|
||||
BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS = ENV_TOKENS.get('BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS', BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS)
|
||||
BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS = ENV_TOKENS.get(
|
||||
'BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS',
|
||||
BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS
|
||||
)
|
||||
# We want Bulk Email running on the high-priority queue, so we define the
|
||||
# routing key that points to it. At the moment, the name is the same.
|
||||
# We have to reset the value here, since we have changed the value of the queue name.
|
||||
@@ -269,6 +272,9 @@ BULK_EMAIL_ROUTING_KEY = HIGH_PRIORITY_QUEUE
|
||||
# we have to reset the value here.
|
||||
BULK_EMAIL_ROUTING_KEY_SMALL_JOBS = LOW_PRIORITY_QUEUE
|
||||
|
||||
# Queue to use for updating persistent grades
|
||||
RECALCULATE_GRADES_ROUTING_KEY = ENV_TOKENS.get('RECALCULATE_GRADES_ROUTING_KEY', LOW_PRIORITY_QUEUE)
|
||||
|
||||
# following setting is for backward compatibility
|
||||
if ENV_TOKENS.get('COMPREHENSIVE_THEME_DIR', None):
|
||||
COMPREHENSIVE_THEME_DIR = ENV_TOKENS.get('COMPREHENSIVE_THEME_DIR')
|
||||
|
||||
@@ -1853,6 +1853,11 @@ BULK_EMAIL_LOG_SENT_EMAILS = False
|
||||
# parallel, and what the SES rate is.
|
||||
BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS = 0.02
|
||||
|
||||
############################# Persistent Grades ####################################
|
||||
|
||||
# Queue to use for updating persistent grades
|
||||
RECALCULATE_GRADES_ROUTING_KEY = LOW_PRIORITY_QUEUE
|
||||
|
||||
############################# Email Opt In ####################################
|
||||
|
||||
# Minimum age for organization-wide email opt in
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
# incorporated into the main project.
|
||||
# https://github.com/onelogin/python-saml/pull/159
|
||||
# https://github.com/onelogin/python-saml/pull/164
|
||||
git+https://github.com/open-craft/python-saml.git@7f7dc389abeba44c1dac154d6aafcbe4187ae221#egg=python-saml==2.1.9
|
||||
git+https://github.com/open-craft/python-saml.git@d50f8d25419c2e981605e5c64e8528a125bcf303#egg=python-saml==2.2.0
|
||||
|
||||
Reference in New Issue
Block a user