Commit 4c35a0f1 by Christina Roberts

Merge pull request #488 from edx/christina/emails

Send e-mails when course creator status changes.
parents 0578175a 087d35c9
...@@ -5,6 +5,10 @@ These are notable changes in edx-platform. This is a rolling list of changes, ...@@ -5,6 +5,10 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected. the top. Include a label indicating the component affected.
Studio: Send e-mails to new Studio users (on edge only) when their course creator
status has changed. This will not be in use until the course creator table
is enabled.
LMS: Added user preferences (arbitrary user/key/value tuples, for which LMS: Added user preferences (arbitrary user/key/value tuples, for which
which user/key is unique) and a REST API for reading users and which user/key is unique) and a REST API for reading users and
preferences. Access to the REST API is restricted by use of the preferences. Access to the REST API is restricted by use of the
......
...@@ -42,7 +42,7 @@ class IndexCourseCreatorTests(CourseTestCase): ...@@ -42,7 +42,7 @@ class IndexCourseCreatorTests(CourseTestCase):
self.disable_course_creation = { self.disable_course_creation = {
"DISABLE_COURSE_CREATION": True, "DISABLE_COURSE_CREATION": True,
"ENABLE_CREATOR_GROUP": True, "ENABLE_CREATOR_GROUP": True,
'STAFF_EMAIL': 'mark@marky.mark', 'STUDIO_REQUEST_EMAIL': 'mark@marky.mark',
} }
self.enable_creator_group = {"ENABLE_CREATOR_GROUP": True} self.enable_creator_group = {"ENABLE_CREATOR_GROUP": True}
......
...@@ -6,7 +6,13 @@ from course_creators.models import CourseCreator, update_creator_state ...@@ -6,7 +6,13 @@ from course_creators.models import CourseCreator, update_creator_state
from course_creators.views import update_course_creator_group from course_creators.views import update_course_creator_group
from django.contrib import admin from django.contrib import admin
from django.conf import settings
from django.dispatch import receiver from django.dispatch import receiver
from mitxmako.shortcuts import render_to_string
import logging
log = logging.getLogger("studio.coursecreatoradmin")
def get_email(obj): def get_email(obj):
...@@ -60,4 +66,25 @@ def update_creator_group_callback(sender, **kwargs): ...@@ -60,4 +66,25 @@ def update_creator_group_callback(sender, **kwargs):
""" """
Callback for when the model's creator status has changed. Callback for when the model's creator status has changed.
""" """
update_course_creator_group(kwargs['caller'], kwargs['user'], kwargs['add']) user = kwargs['user']
updated_state = kwargs['state']
update_course_creator_group(kwargs['caller'], user, updated_state == CourseCreator.GRANTED)
studio_request_email = settings.MITX_FEATURES.get('STUDIO_REQUEST_EMAIL','')
context = {'studio_request_email': studio_request_email}
subject = render_to_string('emails/course_creator_subject.txt', context)
subject = ''.join(subject.splitlines())
if updated_state == CourseCreator.GRANTED:
message_template = 'emails/course_creator_granted.txt'
elif updated_state == CourseCreator.DENIED:
message_template = 'emails/course_creator_denied.txt'
else:
# changed to unrequested or pending
message_template = 'emails/course_creator_revoked.txt'
message = render_to_string(message_template, context)
try:
user.email_user(subject, message, studio_request_email)
except:
log.warning("Unable to send course creator status e-mail to %s", user.email)
...@@ -68,7 +68,7 @@ def post_save_callback(sender, **kwargs): ...@@ -68,7 +68,7 @@ def post_save_callback(sender, **kwargs):
sender=sender, sender=sender,
caller=instance.admin, caller=instance.admin,
user=instance.user, user=instance.user,
add=instance.state == CourseCreator.GRANTED state=instance.state
) )
instance.state_changed = timezone.now() instance.state_changed = timezone.now()
......
...@@ -13,6 +13,11 @@ from course_creators.models import CourseCreator ...@@ -13,6 +13,11 @@ from course_creators.models import CourseCreator
from auth.authz import is_user_in_creator_group from auth.authz import is_user_in_creator_group
def mock_render_to_string(template_name, context):
"""Return a string that encodes template_name and context"""
return str((template_name, context))
class CourseCreatorAdminTest(TestCase): class CourseCreatorAdminTest(TestCase):
""" """
Tests for course creator admin. Tests for course creator admin.
...@@ -32,17 +37,40 @@ class CourseCreatorAdminTest(TestCase): ...@@ -32,17 +37,40 @@ class CourseCreatorAdminTest(TestCase):
self.creator_admin = CourseCreatorAdmin(self.table_entry, AdminSite()) self.creator_admin = CourseCreatorAdmin(self.table_entry, AdminSite())
def test_change_status(self): @mock.patch('course_creators.admin.render_to_string', mock.Mock(side_effect=mock_render_to_string, autospec=True))
@mock.patch('django.contrib.auth.models.User.email_user')
def test_change_status(self, email_user):
""" """
Tests that updates to state impact the creator group maintained in authz.py. Tests that updates to state impact the creator group maintained in authz.py and that e-mails are sent.
""" """
STUDIO_REQUEST_EMAIL = 'mark@marky.mark'
def change_state(state, is_creator): def change_state(state, is_creator):
""" Helper method for changing state """ """ Helper method for changing state """
self.table_entry.state = state self.table_entry.state = state
self.creator_admin.save_model(self.request, self.table_entry, None, True) self.creator_admin.save_model(self.request, self.table_entry, None, True)
self.assertEqual(is_creator, is_user_in_creator_group(self.user)) self.assertEqual(is_creator, is_user_in_creator_group(self.user))
with mock.patch.dict('django.conf.settings.MITX_FEATURES', {"ENABLE_CREATOR_GROUP": True}): context = {'studio_request_email': STUDIO_REQUEST_EMAIL}
if state == CourseCreator.GRANTED:
template = 'emails/course_creator_granted.txt'
elif state == CourseCreator.DENIED:
template = 'emails/course_creator_denied.txt'
else:
template = 'emails/course_creator_revoked.txt'
email_user.assert_called_with(
mock_render_to_string('emails/course_creator_subject.txt', context),
mock_render_to_string(template, context),
STUDIO_REQUEST_EMAIL
)
with mock.patch.dict(
'django.conf.settings.MITX_FEATURES',
{
"ENABLE_CREATOR_GROUP": True,
"STUDIO_REQUEST_EMAIL": STUDIO_REQUEST_EMAIL
}):
# User is initially unrequested. # User is initially unrequested.
self.assertFalse(is_user_in_creator_group(self.user)) self.assertFalse(is_user_in_creator_group(self.user))
......
...@@ -42,8 +42,8 @@ MITX_FEATURES = { ...@@ -42,8 +42,8 @@ MITX_FEATURES = {
# do not display video when running automated acceptance tests # do not display video when running automated acceptance tests
'STUB_VIDEO_FOR_TESTING': False, 'STUB_VIDEO_FOR_TESTING': False,
# email address for staff (eg to request course creation) # email address for studio staff (eg to request course creation)
'STAFF_EMAIL': '', 'STUDIO_REQUEST_EMAIL': '',
'STUDIO_NPS_SURVEY': True, 'STUDIO_NPS_SURVEY': True,
......
<%! from django.utils.translation import ugettext as _ %>
${_("Your request for course creation rights to edX Studio have been denied. If you believe this was in error, please contact: ")}
${ studio_request_email }
<%! from django.utils.translation import ugettext as _ %>
${_("Your request for course creation rights to edX Studio have been granted. To create your first course, visit:")}
% if is_secure:
https://${ site }
% else:
http://${ site }
% endif
<%! from django.utils.translation import ugettext as _ %>
${_("Your course creation rights to edX Studio have been revoked. If you believe this was in error, please contact: ")}
${ studio_request_email }
<%! from django.utils.translation import ugettext as _ %>
${_("Your course creator status for edX Studio")}
...@@ -79,8 +79,8 @@ ...@@ -79,8 +79,8 @@
% if course_creator_status=='granted': % if course_creator_status=='granted':
<a href="#" class="button new-button new-course-button"><i class="icon-plus icon-inline"></i> <a href="#" class="button new-button new-course-button"><i class="icon-plus icon-inline"></i>
${_("New Course")}</a> ${_("New Course")}</a>
% elif course_creator_status=='disallowed_for_this_site' and settings.MITX_FEATURES.get('STAFF_EMAIL',''): % elif course_creator_status=='disallowed_for_this_site' and settings.MITX_FEATURES.get('STUDIO_REQUEST_EMAIL',''):
<a href="mailto:${settings.MITX_FEATURES.get('STAFF_EMAIL','')}">${_("Email staff to create course")}</a> <a href="mailto:${settings.MITX_FEATURES.get('STUDIO_REQUEST_EMAIL','')}">${_("Email staff to create course")}</a>
% endif % endif
</li> </li>
</ul> </ul>
...@@ -252,10 +252,10 @@ ...@@ -252,10 +252,10 @@
</ol> </ol>
</div> </div>
% if course_creator_status=='disallowed_for_this_site' and settings.MITX_FEATURES.get('STAFF_EMAIL',''): % if course_creator_status=='disallowed_for_this_site' and settings.MITX_FEATURES.get('STUDIO_REQUEST_EMAIL',''):
<div class="bit"> <div class="bit">
<h3 class="title title-3">${_('Can I create courses in Studio?')}</h3> <h3 class="title title-3">${_('Can I create courses in Studio?')}</h3>
<p>${_('In order to create courses in Studio, you must')} <a href="mailto:${settings.MITX_FEATURES.get('STAFF_EMAIL','')}">${_("contact edX staff to help you create a course")}</a></p> <p>${_('In order to create courses in Studio, you must')} <a href="mailto:${settings.MITX_FEATURES.get('STUDIO_REQUEST_EMAIL','')}">${_("contact edX staff to help you create a course")}</a></p>
</div> </div>
% endif % endif
......
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