Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send e-mails when course creator status changes. #488

Merged
merged 4 commits into from
Jul 29, 2013
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
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
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
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
Expand Down
2 changes: 1 addition & 1 deletion cms/djangoapps/contentstore/tests/test_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def setUp(self):
self.disable_course_creation = {
"DISABLE_COURSE_CREATION": True,
"ENABLE_CREATOR_GROUP": True,
'STAFF_EMAIL': 'mark@marky.mark',
'STUDIO_REQUEST_EMAIL': 'mark@marky.mark',
}

self.enable_creator_group = {"ENABLE_CREATOR_GROUP": True}
Expand Down
29 changes: 28 additions & 1 deletion cms/djangoapps/course_creators/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
from course_creators.views import update_course_creator_group

from django.contrib import admin
from django.conf import settings
from django.dispatch import receiver
from mitxmako.shortcuts import render_to_string

import logging

log = logging.getLogger("studio.coursecreatoradmin")


def get_email(obj):
Expand Down Expand Up @@ -60,4 +66,25 @@ def update_creator_group_callback(sender, **kwargs):
"""
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)
2 changes: 1 addition & 1 deletion cms/djangoapps/course_creators/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def post_save_callback(sender, **kwargs):
sender=sender,
caller=instance.admin,
user=instance.user,
add=instance.state == CourseCreator.GRANTED
state=instance.state
)

instance.state_changed = timezone.now()
Expand Down
34 changes: 31 additions & 3 deletions cms/djangoapps/course_creators/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
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):
"""
Tests for course creator admin.
Expand All @@ -32,17 +37,40 @@ def setUp(self):

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):
""" Helper method for changing state """
self.table_entry.state = state
self.creator_admin.save_model(self.request, self.table_entry, None, True)
self.assertEqual(is_creator, is_user_in_creator_group(self.user))

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
}):

with mock.patch.dict('django.conf.settings.MITX_FEATURES', {"ENABLE_CREATOR_GROUP": True}):
# User is initially unrequested.
self.assertFalse(is_user_in_creator_group(self.user))

Expand Down
4 changes: 2 additions & 2 deletions cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
# do not display video when running automated acceptance tests
'STUB_VIDEO_FOR_TESTING': False,

# email address for staff (eg to request course creation)
'STAFF_EMAIL': '',
# email address for studio staff (eg to request course creation)
'STUDIO_REQUEST_EMAIL': '',

'STUDIO_NPS_SURVEY': True,

Expand Down
5 changes: 5 additions & 0 deletions cms/templates/emails/course_creator_denied.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%! 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: ")}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The I18N here is good, but - curious - how will the template decide which language to use here? Ideally, this would be part of some user preference. However, setting email language preferences is out-of-scope for this story :-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah, you are right. I have no idea how we will handle a user e-mail language preference.

Definitely TBD.


${ studio_request_email }
9 changes: 9 additions & 0 deletions cms/templates/emails/course_creator_granted.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<%! 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
5 changes: 5 additions & 0 deletions cms/templates/emails/course_creator_revoked.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%! 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 }
2 changes: 2 additions & 0 deletions cms/templates/emails/course_creator_subject.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<%! from django.utils.translation import ugettext as _ %>
${_("Your course creator status for edX Studio")}
8 changes: 4 additions & 4 deletions cms/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ <h3 class="sr">${_("Page Actions")}</h3>
% if course_creator_status=='granted':
<a href="#" class="button new-button new-course-button"><i class="icon-plus icon-inline"></i>
${_("New Course")}</a>
% elif course_creator_status=='disallowed_for_this_site' and settings.MITX_FEATURES.get('STAFF_EMAIL',''):
<a href="mailto:${settings.MITX_FEATURES.get('STAFF_EMAIL','')}">${_("Email staff to create course")}</a>
% elif course_creator_status=='disallowed_for_this_site' and settings.MITX_FEATURES.get('STUDIO_REQUEST_EMAIL',''):
<a href="mailto:${settings.MITX_FEATURES.get('STUDIO_REQUEST_EMAIL','')}">${_("Email staff to create course")}</a>
% endif
</li>
</ul>
Expand Down Expand Up @@ -252,10 +252,10 @@ <h3 class="title title-3">${_('Need help?')}</h3>
</ol>
</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">
<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>
% endif

Expand Down