Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 33 additions & 10 deletions lms/djangoapps/bulk_enroll/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from rest_framework.test import APIRequestFactory, APITestCase, force_authenticate

from common.djangoapps.student.models import ( # lint-amnesty, pylint: disable=line-too-long
ENROLLED_TO_ENROLLED,
ENROLLED_TO_UNENROLLED,
UNENROLLED_TO_ENROLLED,
CourseEnrollment,
Expand Down Expand Up @@ -148,6 +149,9 @@ def test_invalid_email(self):
{
"identifier": 'percivaloctavius@',
"invalidIdentifier": True,
"success": False,
"error_type": "invalid_identifier",
"error_message": "Invalid email address",
}
]
}
Expand Down Expand Up @@ -180,6 +184,9 @@ def test_invalid_username(self):
{
"identifier": 'percivaloctavius',
"invalidIdentifier": True,
"success": False,
"error_type": "invalid_identifier",
"error_message": "Invalid email address",
}
]
}
Expand Down Expand Up @@ -222,7 +229,9 @@ def test_enroll_with_username(self):
"auto_enroll": False,
"user": True,
"allowed": False,
}
},
"success": True,
"state_transition": UNENROLLED_TO_ENROLLED,
}
]
}
Expand Down Expand Up @@ -272,7 +281,9 @@ def test_enroll_with_email(self, use_json):
"auto_enroll": False,
"user": True,
"allowed": False,
}
},
"success": True,
"state_transition": UNENROLLED_TO_ENROLLED,
}
]
}
Expand Down Expand Up @@ -326,7 +337,9 @@ def test_unenroll(self, use_json):
"auto_enroll": False,
"user": True,
"allowed": False,
}
},
"success": True,
"state_transition": ENROLLED_TO_UNENROLLED,
}
]
}
Expand Down Expand Up @@ -430,7 +443,9 @@ def test_add_to_valid_cohort(self):
"user": True,
"allowed": False,
"cohort": 'cohort1',
}
},
"success": True,
"state_transition": UNENROLLED_TO_ENROLLED,
}
]
}
Expand All @@ -444,7 +459,7 @@ def test_add_to_valid_cohort(self):

assert res_json == expected

def test_readd_to_different_cohort(self):
def test_read_to_different_cohort(self):
config_course_cohorts(self.course, is_cohorted=True, manual_cohorts=["cohort1", "cohort2"])
response = self.request_bulk_enroll({
'identifiers': self.notenrolled_student.username,
Expand Down Expand Up @@ -481,7 +496,9 @@ def test_readd_to_different_cohort(self):
"user": True,
"allowed": False,
"cohort": 'cohort1',
}
},
"success": True,
"state_transition": UNENROLLED_TO_ENROLLED,
}
]
}
Expand Down Expand Up @@ -529,7 +546,9 @@ def test_readd_to_different_cohort(self):
"user": True,
"allowed": False,
"cohort": 'cohort2',
}
},
"success": True,
"state_transition": ENROLLED_TO_ENROLLED,
}
]
}
Expand All @@ -539,7 +558,7 @@ def test_readd_to_different_cohort(self):
assert get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)) is not None
assert res2_json == expected2

def test_readd_to_same_cohort(self):
def test_read_to_same_cohort(self):
config_course_cohorts(self.course, is_cohorted=True, manual_cohorts=["cohort1", "cohort2"])
response = self.request_bulk_enroll({
'identifiers': self.notenrolled_student.username,
Expand Down Expand Up @@ -576,7 +595,9 @@ def test_readd_to_same_cohort(self):
"user": True,
"allowed": False,
"cohort": 'cohort1',
}
},
"success": True,
"state_transition": UNENROLLED_TO_ENROLLED,
}
]
}
Expand Down Expand Up @@ -625,7 +646,9 @@ def test_readd_to_same_cohort(self):
"user": True,
"allowed": False,
"cohort": 'cohort1',
}
},
"success": True,
"state_transition": ENROLLED_TO_ENROLLED,
}
]
}
Expand Down
14 changes: 9 additions & 5 deletions lms/djangoapps/bulk_enroll/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
"""


import json

from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
Expand All @@ -15,7 +13,7 @@

from common.djangoapps.util.disable_rate_limit import can_disable_rate_limit
from lms.djangoapps.bulk_enroll.serializers import BulkEnrollmentSerializer
from lms.djangoapps.instructor.views.api import students_update_enrollment
from lms.djangoapps.instructor.views.api import StudentsUpdateEnrollmentView
from openedx.core.djangoapps.course_groups.cohorts import add_user_to_cohort, get_cohort_by_name
from openedx.core.djangoapps.course_groups.models import CourseUserGroup
from openedx.core.djangoapps.enrollments.views import EnrollmentUserThrottle
Expand Down Expand Up @@ -89,8 +87,14 @@ def post(self, request): # lint-amnesty, pylint: disable=missing-function-docst
}
for course_id, cohort_name in zip_longest(serializer.data.get('courses'),
serializer.data.get('cohorts', [])):
response = students_update_enrollment(self.request, course_id=course_id)
response_content = json.loads(response.content.decode('utf-8'))
# Internal request to DRF view
view = StudentsUpdateEnrollmentView()
response_content = view._process_student_enrollment( # pylint: disable=protected-access
request=request,
course_id=course_id,
data=request.data,
secure=request.is_secure()
)

if cohort_name:
try:
Expand Down
36 changes: 35 additions & 1 deletion lms/djangoapps/instructor/enrollment.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
from datetime import datetime

import pytz
from crum import get_current_request
from django.conf import settings
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.contrib.sites.models import Site
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils.translation import override as override_language
Expand Down Expand Up @@ -50,7 +52,9 @@
)
from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.theming.helpers import get_current_site
from openedx.core.djangoapps.user_api.models import UserPreference
from openedx.core.lib.celery.task_utils import emulate_http_request
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.exceptions import ItemNotFoundError # lint-amnesty, pylint: disable=wrong-import-order

Expand Down Expand Up @@ -591,7 +595,37 @@ def send_mail_to_student(student, param_dict, language=None):
language=language,
user_context=param_dict,
)
ace.send(message)

current_request = get_current_request()

if current_request is None:
# We're in a Celery task context, need to emulate HTTP request
site = get_current_site()
if not site:
try:
site = Site.objects.get(id=settings.SITE_ID)
except Site.DoesNotExist:
try:
site = Site.objects.first()
except Exception: # pylint: disable=broad-except
site = None

# Get the recipient user for tracking purposes
user = None
if lms_user_id and lms_user_id > 0:
try:
user = User.objects.get(id=lms_user_id)
except User.DoesNotExist:
pass

# Use emulate_http_request to provide the necessary context for template tags
# that require a request object, such as google_analytics_tracking_pixel
with emulate_http_request(site=site, user=user):
ace.send(message)
else:
# We're in a web context, just send the message directly
# The current request already provides the necessary context
ace.send(message)


def render_message_to_string(subject_template, message_template, param_dict, language=None):
Expand Down
12 changes: 12 additions & 0 deletions lms/djangoapps/instructor/message_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,15 @@ class RemoveBetaTester(BaseMessageType):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.options['transactional'] = True


class BatchEnrollment(BaseMessageType):
"""
A message for instructors when they finish the batch enrollment async process.
"""

APP_LABEL = "instructor"

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.options["transactional"] = True
Loading
Loading