Commit 4eef6108 by Awais Qureshi

Merge pull request #8328 from edx/awais786/awais786/ECOM-1572-icrv-emails-format-new

ECOM-1572 implementing code to new branch.
parents 9bdf64d3 424e1f5b
...@@ -20,15 +20,17 @@ from django.core.urlresolvers import reverse ...@@ -20,15 +20,17 @@ from django.core.urlresolvers import reverse
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core import mail from django.core import mail
from django.test import TestCase from django.test import TestCase
from django.test.client import Client from django.test.client import Client, RequestFactory
from django.test.utils import override_settings from django.test.utils import override_settings
from django.utils import timezone from django.utils import timezone
from opaque_keys.edx.locations import SlashSeparatedCourseKey from opaque_keys.edx.locations import SlashSeparatedCourseKey
from opaque_keys.edx.locator import CourseLocator from opaque_keys.edx.locator import CourseLocator
from opaque_keys.edx.keys import UsageKey
from course_modes.models import CourseMode from course_modes.models import CourseMode
from course_modes.tests.factories import CourseModeFactory from course_modes.tests.factories import CourseModeFactory
from courseware.url_helpers import get_redirect_url
from commerce.tests import TEST_PAYMENT_DATA, TEST_API_URL, TEST_API_SIGNING_KEY from commerce.tests import TEST_PAYMENT_DATA, TEST_API_URL, TEST_API_SIGNING_KEY
from embargo.test_utils import restrict_course from embargo.test_utils import restrict_course
from microsite_configuration import microsite from microsite_configuration import microsite
...@@ -1891,6 +1893,7 @@ class TestEmailMessageWithCustomICRVBlock(ModuleStoreTestCase): ...@@ -1891,6 +1893,7 @@ class TestEmailMessageWithCustomICRVBlock(ModuleStoreTestCase):
self.course_key = SlashSeparatedCourseKey("Robot", "999", "Test_Course") self.course_key = SlashSeparatedCourseKey("Robot", "999", "Test_Course")
self.course = CourseFactory.create(org='Robot', number='999', display_name='Test Course') self.course = CourseFactory.create(org='Robot', number='999', display_name='Test Course')
self.due_date = datetime(2015, 6, 22, tzinfo=pytz.UTC) self.due_date = datetime(2015, 6, 22, tzinfo=pytz.UTC)
self.allowed_attempts = 1
# Create the course modes # Create the course modes
for mode in ('audit', 'honor', 'verified'): for mode in ('audit', 'honor', 'verified'):
...@@ -1906,7 +1909,7 @@ class TestEmailMessageWithCustomICRVBlock(ModuleStoreTestCase): ...@@ -1906,7 +1909,7 @@ class TestEmailMessageWithCustomICRVBlock(ModuleStoreTestCase):
parent=vertical, parent=vertical,
category='edx-reverification-block', category='edx-reverification-block',
display_name='Test Verification Block', display_name='Test Verification Block',
metadata={'attempts': 3, 'due': self.due_date} metadata={'attempts': self.allowed_attempts, 'due': self.due_date}
) )
self.section_location = section.location self.section_location = section.location
...@@ -1940,73 +1943,148 @@ class TestEmailMessageWithCustomICRVBlock(ModuleStoreTestCase): ...@@ -1940,73 +1943,148 @@ class TestEmailMessageWithCustomICRVBlock(ModuleStoreTestCase):
status='submitted' status='submitted'
) )
self.attempt = SoftwareSecurePhotoVerification.objects.filter(user=self.user) self.attempt = SoftwareSecurePhotoVerification.objects.filter(user=self.user)
location_id = VerificationStatus.get_location_id(self.attempt)
usage_key = UsageKey.from_string(location_id)
redirect_url = get_redirect_url(self.course_key, usage_key.replace(course_key=self.course_key))
self.request = RequestFactory().get('/url')
self.course_link = self.request.build_absolute_uri(redirect_url)
def test_approved_email_message(self): def test_approved_email_message(self):
"""
Test email message for approved photo verification.
"""
subject, body = _compose_message_reverification_email( subject, body = _compose_message_reverification_email(
self.course.id, self.user.id, self.reverification_location, "approved", True self.course.id, self.user.id, self.reverification_location, "approved", self.request
) )
self.assertIn( self.assertIn(
"Your verification for course {course_name} and assessment {assessment} has been passed.".format( "We have successfully verified your identity for the {assessment} "
course_name=self.course.display_name_with_default, "assessment in the {course_name} course.".format(
assessment=self.assessment assessment=self.assessment,
course_name=self.course.display_name_with_default
), ),
body body
) )
self.check_courseware_link_exists(body)
self.assertIn("Re-verification Status", subject) self.assertIn("Re-verification Status", subject)
def test_denied_email_message_with_valid_due_date_and_attempts_allowed(self): def test_denied_email_message_with_valid_due_date_and_attempts_allowed(self):
__, body = _compose_message_reverification_email( subject, body = _compose_message_reverification_email(
self.course.id, self.user.id, self.reverification_location, "denied", True self.course.id, self.user.id, self.reverification_location, "denied", self.request
) )
self.assertIn( self.assertIn(
"Your verification for course {course_name} and assessment {assessment} has failed.".format( "We could not verify your identity for the {assessment} assessment "
"in the {course_name} course. You have used "
"{used_attempts} out of {allowed_attempts} attempts to "
"verify your identity.".format(
course_name=self.course.display_name_with_default, course_name=self.course.display_name_with_default,
assessment=self.assessment assessment=self.assessment,
used_attempts=1,
allowed_attempts=self.allowed_attempts + 1
),
body
)
self.assertIn(
"You must verify your identity before the assessment "
"closes on {due_date}".format(
due_date=get_default_time_display(self.due_date)
), ),
body body
) )
reverify_link = self.request.build_absolute_uri(self.re_verification_link)
self.assertIn(
"To try to verify your identity again, select the following link:",
body
)
self.assertIn(reverify_link, body)
self.assertIn("Re-verification Status", subject)
def test_denied_email_message_with_due_date_and_no_attempts(self):
""" Denied email message if due date is still open but user has no
attempts available.
"""
VerificationStatus.add_verification_status(
checkpoint=self.check_point,
user=self.user,
status='submitted'
)
__, body = _compose_message_reverification_email(
self.course.id, self.user.id, self.reverification_location, "denied", self.request
)
self.assertIn("Assessment closes on {due_date}".format(due_date=get_default_time_display(self.due_date)), body)
self.assertIn("Click on link below to re-verify", body)
self.assertIn( self.assertIn(
"https://{}{}".format( "We could not verify your identity for the {assessment} assessment "
microsite.get_value('SITE_NAME', 'localhost'), self.re_verification_link "in the {course_name} course. You have used "
"{used_attempts} out of {allowed_attempts} attempts to "
"verify your identity, and verification is no longer "
"possible".format(
course_name=self.course.display_name_with_default,
assessment=self.assessment,
used_attempts=2,
allowed_attempts=self.allowed_attempts + 1
), ),
body body
) )
self.check_courseware_link_exists(body)
def test_denied_email_message_with_close_verification_dates(self): def test_denied_email_message_with_close_verification_dates(self):
# Due date given and expired
return_value = datetime(2016, 1, 1, tzinfo=timezone.utc) return_value = datetime(2016, 1, 1, tzinfo=timezone.utc)
with patch.object(timezone, 'now', return_value=return_value): with patch.object(timezone, 'now', return_value=return_value):
__, body = _compose_message_reverification_email( __, body = _compose_message_reverification_email(
self.course.id, self.user.id, self.reverification_location, "denied", True self.course.id, self.user.id, self.reverification_location, "denied", self.request
) )
self.assertIn( self.assertIn(
"Your verification for course {course_name} and assessment {assessment} has failed.".format( "We could not verify your identity for the {assessment} assessment "
"in the {course_name} course. You have used "
"{used_attempts} out of {allowed_attempts} attempts to "
"verify your identity, and verification is no longer "
"possible".format(
course_name=self.course.display_name_with_default, course_name=self.course.display_name_with_default,
assessment=self.assessment assessment=self.assessment,
used_attempts=1,
allowed_attempts=self.allowed_attempts + 1
), ),
body body
) )
self.assertIn("Assessment date has passed and retake not allowed", body)
def test_check_num_queries(self): def test_check_num_queries(self):
# Get the re-verification block to check the call made # Get the re-verification block to check the call made
with check_mongo_calls(2): with check_mongo_calls(1):
ver_block = modulestore().get_item(self.reverification.location) ver_block = modulestore().get_item(self.reverification.location)
# Expect that the verification block is fetched # Expect that the verification block is fetched
self.assertIsNotNone(ver_block) self.assertIsNotNone(ver_block)
def check_courseware_link_exists(self, body):
"""Checking courseware url and signature information of EDX"""
self.assertIn(
"To go to the courseware, select the following link:",
body
)
self.assertIn(
"{course_link}".format(
course_link=self.course_link
),
body
)
self.assertIn("Thanks,", body)
self.assertIn(
"The {platform_name} team".format(
platform_name=settings.PLATFORM_NAME
),
body
)
class TestEmailMessageWithDefaultICRVBlock(ModuleStoreTestCase): class TestEmailMessageWithDefaultICRVBlock(ModuleStoreTestCase):
""" """
...@@ -2059,6 +2137,7 @@ class TestEmailMessageWithDefaultICRVBlock(ModuleStoreTestCase): ...@@ -2059,6 +2137,7 @@ class TestEmailMessageWithDefaultICRVBlock(ModuleStoreTestCase):
) )
self.check_point.add_verification_attempt(SoftwareSecurePhotoVerification.objects.create(user=self.user)) self.check_point.add_verification_attempt(SoftwareSecurePhotoVerification.objects.create(user=self.user))
self.attempt = SoftwareSecurePhotoVerification.objects.filter(user=self.user) self.attempt = SoftwareSecurePhotoVerification.objects.filter(user=self.user)
self.request = RequestFactory().get('/url')
def test_denied_email_message_with_no_attempt_allowed(self): def test_denied_email_message_with_no_attempt_allowed(self):
...@@ -2069,73 +2148,25 @@ class TestEmailMessageWithDefaultICRVBlock(ModuleStoreTestCase): ...@@ -2069,73 +2148,25 @@ class TestEmailMessageWithDefaultICRVBlock(ModuleStoreTestCase):
) )
__, body = _compose_message_reverification_email( __, body = _compose_message_reverification_email(
self.course.id, self.user.id, self.reverification_location, "denied", True self.course.id, self.user.id, self.reverification_location, "denied", self.request
)
self.assertIn(
"Your verification for course {course_name} and assessment {assessment} has failed.".format(
course_name=self.course.display_name_with_default,
assessment=self.assessment
),
body
)
self.assertIn("You have reached your allowed attempts limit. No more retakes allowed.", body)
def test_due_date(self):
self.reverification.due = datetime.now()
self.reverification.save()
VerificationStatus.add_verification_status(
checkpoint=self.check_point,
user=self.user,
status='submitted'
)
__, body = _compose_message_reverification_email(
self.course.id, self.user.id, self.reverification_location, "denied", True
) )
self.assertIn( self.assertIn(
"Your verification for course {course_name} and assessment {assessment} has failed.".format( "We could not verify your identity for the {assessment} assessment "
"in the {course_name} course. You have used "
"{used_attempts} out of {allowed_attempts} attempts to "
"verify your identity, and verification is no longer "
"possible".format(
course_name=self.course.display_name_with_default, course_name=self.course.display_name_with_default,
assessment=self.assessment assessment=self.assessment,
), used_attempts=1,
body allowed_attempts=1
)
self.assertIn("You have reached your allowed attempts limit. No more retakes allowed.", body)
def test_denied_email_message_with_no_due_date(self):
VerificationStatus.add_verification_status(
checkpoint=self.check_point,
user=self.user,
status='error'
)
__, body = _compose_message_reverification_email(
self.course.id, self.user.id, self.reverification_location, "denied", True
)
self.assertIn(
"Your verification for course {course_name} and assessment {assessment} has failed.".format(
course_name=self.course.display_name_with_default,
assessment=self.assessment
),
body
)
self.assertIn("Assessment is open and you have 1 attempt(s) remaining.", body)
self.assertIn("Click on link below to re-verify", body)
self.assertIn(
"https://{}{}".format(
microsite.get_value('SITE_NAME', 'localhost'), self.re_verification_link
), ),
body body
) )
def test_error_on_compose_email(self): def test_error_on_compose_email(self):
resp = _compose_message_reverification_email( resp = _compose_message_reverification_email(
self.course.id, self.user.id, u'i4x://edX/DemoX/edx-reverification-block/invalid_location', "denied", True self.course.id, self.user.id, self.reverification_location, "denied", True
) )
self.assertIsNone(resp) self.assertIsNone(resp)
...@@ -858,7 +858,7 @@ def submit_photos_for_verification(request): ...@@ -858,7 +858,7 @@ def submit_photos_for_verification(request):
def _compose_message_reverification_email( def _compose_message_reverification_email(
course_key, user_id, related_assessment_location, status, is_secure course_key, user_id, related_assessment_location, status, request
): # pylint: disable=invalid-name ): # pylint: disable=invalid-name
""" """
Compose subject and message for photo reverification email. Compose subject and message for photo reverification email.
...@@ -885,14 +885,13 @@ def _compose_message_reverification_email( ...@@ -885,14 +885,13 @@ def _compose_message_reverification_email(
context = { context = {
"status": status, "status": status,
"course_name": course.display_name_with_default, "course_name": course.display_name_with_default,
"assessment": reverification_block.related_assessment, "assessment": reverification_block.related_assessment
"courseware_url": redirect_url
} }
# Allowed attempts is 1 if not set on verification block # Allowed attempts is 1 if not set on verification block
allowed_attempts = 1 if reverification_block.attempts == 0 else reverification_block.attempts allowed_attempts = reverification_block.attempts + 1
user_attempts = VerificationStatus.get_user_attempts(user_id, course_key, related_assessment_location) used_attempts = VerificationStatus.get_user_attempts(user_id, course_key, related_assessment_location)
left_attempts = allowed_attempts - user_attempts left_attempts = allowed_attempts - used_attempts
is_attempt_allowed = left_attempts > 0 is_attempt_allowed = left_attempts > 0
verification_open = True verification_open = True
if reverification_block.due: if reverification_block.due:
...@@ -902,9 +901,11 @@ def _compose_message_reverification_email( ...@@ -902,9 +901,11 @@ def _compose_message_reverification_email(
context["is_attempt_allowed"] = is_attempt_allowed context["is_attempt_allowed"] = is_attempt_allowed
context["verification_open"] = verification_open context["verification_open"] = verification_open
context["due_date"] = get_default_time_display(reverification_block.due) context["due_date"] = get_default_time_display(reverification_block.due)
context["is_secure"] = is_secure
context["site"] = microsite.get_value('SITE_NAME', 'localhost') context['platform_name'] = settings.PLATFORM_NAME
context['platform_name'] = microsite.get_value('platform_name', settings.PLATFORM_NAME), context["used_attempts"] = used_attempts
context["allowed_attempts"] = allowed_attempts
context["support_link"] = microsite.get_value('email_from_address', settings.CONTACT_EMAIL)
re_verification_link = reverse( re_verification_link = reverse(
'verify_student_incourse_reverify', 'verify_student_incourse_reverify',
...@@ -913,7 +914,10 @@ def _compose_message_reverification_email( ...@@ -913,7 +914,10 @@ def _compose_message_reverification_email(
related_assessment_location related_assessment_location
) )
) )
context["reverify_link"] = re_verification_link
context["course_link"] = request.build_absolute_uri(redirect_url)
context["reverify_link"] = request.build_absolute_uri(re_verification_link)
message = render_to_string('emails/reverification_processed.txt', context) message = render_to_string('emails/reverification_processed.txt', context)
log.info( log.info(
"Sending email to User_Id=%s. Attempts left for this user are %s. " "Sending email to User_Id=%s. Attempts left for this user are %s. "
...@@ -1030,7 +1034,7 @@ def results_callback(request): ...@@ -1030,7 +1034,7 @@ def results_callback(request):
related_assessment_location = checkpoints[0].checkpoint_location related_assessment_location = checkpoints[0].checkpoint_location
subject, message = _compose_message_reverification_email( subject, message = _compose_message_reverification_email(
course_key, user_id, related_assessment_location, status, request.is_secure() course_key, user_id, related_assessment_location, status, request
) )
_send_email(user_id, subject, message) _send_email(user_id, subject, message)
......
<%namespace file="../main.html" import="stanford_theme_enabled" /> <%namespace file="../main.html" import="stanford_theme_enabled" />
<%! from django.utils.translation import ugettext as _ %> <%! from django.utils.translation import ugettext as _ %>
% if status == "approved": % if status == "approved":
${_("Your verification for course {course_name} and assessment {assessment} " ${_("We have successfully verified your identity for the {assessment} assessment in the {course_name} course."
"has been passed." ).format(course_name=course_name, assessment=assessment)}
).format(course_name=course_name, assessment=assessment)}
%else: % elif is_attempt_allowed and verification_open: # if attempts are allowed and verification is still open.
${_("Your verification for course {course_name} and assessment {assessment} " ${_("We could not verify your identity for the {assessment} assessment in the {course_name} course. You have used {used_attempts} out of {allowed_attempts} attempts to verify your identity."
"has failed." ).format(course_name=course_name, assessment=assessment, used_attempts=used_attempts, allowed_attempts=allowed_attempts)}
).format(course_name=course_name, assessment=assessment)} %if due_date:
${_("You must verify your identity before the assessment closes on {due_date}.").format(due_date=due_date)}
%endif
% if not is_attempt_allowed: ${_("To try to verify your identity again, select the following link:")}
${_("You have reached your allowed attempts limit. No more retakes allowed.")} ${reverify_link}
% elif not verification_open:
${_("Assessment date has passed and retake not allowed.")}
% else:
% if due_date:
${_("Assessment closes on {due_date}.".format(due_date=due_date))}
% else:
${_("Assessment is open and you have {left_attempts} attempt(s) remaining.".format(left_attempts=left_attempts))}
% endif
${_("Click on link below to re-verify:")} % elif not is_attempt_allowed or not verification_open: # if attempts are not allowed or verification window is closed
% if is_secure: ${_("We could not verify your identity for the {assessment} assessment in the {course_name} course. You have used {used_attempts} out of {allowed_attempts} attempts to verify your identity, and verification is no longer possible."
https://${ site }${ reverify_link } ).format(course_name=course_name, assessment=assessment, used_attempts=used_attempts, allowed_attempts=allowed_attempts)}
% else: %endif
http://${ site }${ reverify_link }
% endif
% endif ${_("To go to the courseware, select the following link:")}
% endif ${course_link}
${_("Click on link below to go to the courseware:")} ${_("If you have any questions, you can contact student support at {support_link}.").format(support_link=support_link)}
% if is_secure:
https://${ site }${ courseware_url }
% else:
http://${ site }${ courseware_url }
% endif
${_("Thanks,")}
${_("The {platform_name} team").format(platform_name=platform_name)}
${_("The {platform_name} Team.").format(platform_name=platform_name)}
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