Commit 91c31e12 by Julia Hansbrough Committed by Brian Wilson

Implemented bulk email interface for new dashboard

parent 014089e6
......@@ -40,6 +40,12 @@ import analytics.distributions
import analytics.csvs
import csv
from bulk_email.models import CourseEmail
from html_to_text import html_to_text
from bulk_email import tasks
from pudb import set_trace
log = logging.getLogger(__name__)
......@@ -705,6 +711,45 @@ def list_forum_members(request, course_id):
}
return JsonResponse(response_payload)
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
# todo check if staff is the desired access level
# todo do html and plaintext messages
@require_level('staff')
@require_query_params(send_to="sending to whom", subject="subject line", message="message text")
def send_email(request, course_id):
"""
Send an email to self, staff, or everyone involved in a course.
Query Paramaters:
- 'send_to' specifies what group the email should be sent to
- 'subject' specifies email's subject
- 'message' specifies email's content
"""
set_trace()
course = get_course_by_id(course_id)
has_instructor_access = has_access(request.user, course, 'instructor')
send_to = request.GET.get("send_to")
subject = request.GET.get("subject")
message = request.GET.get("message")
text_message = html_to_text(message)
if subject == "":
return HttpResponseBadRequest("Operation requires instructor access.")
email = CourseEmail(
course_id = course_id,
sender=request.user,
to_option=send_to,
subject=subject,
html_message=message,
text_message=text_message
)
email.save()
tasks.delegate_email_batches.delay(
email.id,
request.user.id
)
response_payload = {
'course_id': course_id,
}
return JsonResponse(response_payload)
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
......@@ -769,7 +814,6 @@ def update_forum_role_membership(request, course_id):
}
return JsonResponse(response_payload)
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
......
......@@ -2,7 +2,6 @@
Instructor API endpoint urls.
"""
from django.conf.urls import patterns, url
urlpatterns = patterns('', # nopep8
......@@ -34,4 +33,6 @@ urlpatterns = patterns('', # nopep8
'instructor.views.api.update_forum_role_membership', name="update_forum_role_membership"),
url(r'^proxy_legacy_analytics$',
'instructor.views.api.proxy_legacy_analytics', name="proxy_legacy_analytics"),
url(r'^send_email$',
'instructor.views.api.send_email', name="send_email")
)
......@@ -10,6 +10,10 @@ from django.core.urlresolvers import reverse
from django.utils.html import escape
from django.http import Http404
from xmodule_modifiers import wrap_xmodule
from xmodule.html_module import HtmlDescriptor
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
from courseware.access import has_access
from courseware.courses import get_course_by_id
from django_comment_client.utils import has_forum_access
......@@ -17,7 +21,6 @@ from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR
from xmodule.modulestore.django import modulestore
from student.models import CourseEnrollment
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
def instructor_dashboard_2(request, course_id):
......@@ -42,7 +45,8 @@ def instructor_dashboard_2(request, course_id):
_section_membership(course_id, access),
_section_student_admin(course_id, access),
_section_data_download(course_id),
_section_analytics(course_id),
_section_send_email(course_id, access,course),
_section_analytics(course_id)
]
context = {
......@@ -140,6 +144,18 @@ def _section_data_download(course_id):
}
return section_data
def _section_send_email(course_id, access,course):
""" Provide data for the corresponding bulk email section """
html_module = HtmlDescriptor(course.system, DictFieldData({'data': ''}), ScopeIds(None, None, None, None))
section_data = {
'section_key': 'send_email',
'section_display_name': _('Email'),
'access': access,
'send_email': reverse('send_email',kwargs={'course_id': course_id}),
'editor': wrap_xmodule(html_module.get_html, html_module, 'xmodule_edit.html')()
}
return section_data
def _section_analytics(course_id):
""" Provide data for the corresponding dashboard section """
......
......@@ -62,7 +62,6 @@ from bulk_email.models import CourseEmail
from html_to_text import html_to_text
from bulk_email import tasks
log = logging.getLogger(__name__)
# internal commands for managing forum roles:
......
......@@ -114,7 +114,7 @@ MITX_FEATURES = {
# analytics experiments
'ENABLE_INSTRUCTOR_ANALYTICS': False,
'ENABLE_INSTRUCTOR_EMAIL': False,
'ENABLE_INSTRUCTOR_EMAIL': True,
# enable analytics server.
# WARNING: THIS SHOULD ALWAYS BE SET TO FALSE UNDER NORMAL
......
......@@ -157,6 +157,9 @@ setup_instructor_dashboard_sections = (idash_content) ->
constructor: window.InstructorDashboard.sections.StudentAdmin
$element: idash_content.find ".#{CSS_IDASH_SECTION}#student_admin"
,
constructor: window.InstructorDashboard.sections.Email
$element: idash_content.find ".#{CSS_IDASH_SECTION}#send_email"
,
constructor: window.InstructorDashboard.sections.Analytics
$element: idash_content.find ".#{CSS_IDASH_SECTION}#analytics"
]
......
# Email Section
# imports from other modules.
# wrap in (-> ... apply) to defer evaluation
# such that the value can be defined later than this assignment (file load order).
plantTimeout = -> window.InstructorDashboard.util.plantTimeout.apply this, arguments
std_ajax_err = -> window.InstructorDashboard.util.std_ajax_err.apply this, arguments
class SendEmail
constructor: (@$container) ->
# gather elements
@$emailEditor = XModule.loadModule($('.xmodule_edit'));
@$send_to = @$container.find("select[name='send_to']'")
@$subject = @$container.find("input[name='subject']'")
#message = emailEditor.save()['data']
@$btn_send = @$container.find("input[name='send']'")
@$task_response = @$container.find(".request-response")
@$request_response_error = @$container.find(".request-response-error")
# attach click handlers
@$btn_send.click =>
send_data =
action: 'send'
send_to: @$send_to.val()
subject: @$subject.val()
message: @$emailEditor.save()['data']
#message: @$message.val()
$.ajax
dataType: 'json'
url: @$btn_send.data 'endpoint'
data: send_data
success: (data) => @display_response "Your email was successfully queued for sending."
error: std_ajax_err => @fail_with_error "Error sending email."
fail_with_error: (msg) ->
console.warn msg
@$task_response.empty()
@$request_response_error.empty()
@$request_response_error.text msg
display_response: (data_from_server) ->
@$task_response.empty()
@$request_response_error.empty()
@$task_response.text("Your email was successfully queued for sending.")
# Email Section
class Email
# enable subsections.
constructor: (@$section) ->
# attach self to html
# so that instructor_dashboard.coffee can find this object
# to call event handlers like 'onClickTitle'
@$section.data 'wrapper', @
# isolate # initialize SendEmail subsection
plantTimeout 0, => new SendEmail @$section.find '.send-email'
# handler for when the section title is clicked.
onClickTitle: ->
# export for use
# create parent namespaces if they do not already exist.
# abort if underscore can not be found.
if _?
_.defaults window, InstructorDashboard: {}
_.defaults window.InstructorDashboard, sections: {}
_.defaults window.InstructorDashboard.sections,
Email: Email
......@@ -110,6 +110,10 @@ section.instructor-dashboard-content-2 {
}
}
.instructor-dashboard-wrapper-2 section.idash-section#email {
// todo
}
.instructor-dashboard-wrapper-2 section.idash-section#course_info {
.course-errors-wrapper {
......
<%! from django.utils.translation import ugettext as _ %>
<%page args="section_data"/>
<h2>Email</h2>
<form>
<ul class="list-fields">
<li class="field">
<label for="id_to">${_("Send to:")}</label>
<select id="id_to" name="to_option">
<option value="myself">${_("Myself")}</option>
%if to_option == "staff":
<option value="staff" selected="selected">${_("Staff and instructors")}</option>
%else:
<option value="staff">${_("Staff and instructors")}</option>
%endif
%if to_option == "all":
<option value="all" selected="selected">${_("All (students, staff and instructors)")}</option>
%else:
<option value="all">${_("All (students, staff and instructors)")}</option>
%endif
</select>
</li>
<li class="field">
<label for="id_subject">${_("Subject: ")}</label>
%if subject:
<input type="text" id="id_subject" name="subject" maxlength="100" size="75" value="${subject}">
%else:
<input type="text" id="id_subject" name="subject" maxlength="100" size="75">
%endif
</li>
<li class="field">
<label>Message:</label>
<div class="email-editor">
<!--todo make this render the real way-->
<section class="xmodule_edit xmodule_HtmlDescriptor" data-type="HTMLEditingDescriptor">
<section class="html-editor editor">
<div class="row">
<textarea class="tiny-mce">&lt;p&gt;hihihi&lt;/p&gt;</textarea>
</div>
</section>
</section>
</div>
<input type="hidden" name="message" value="">
</li>
</ul>
<div class="submit-email-action">
${_("Please try not to email students more than once a day. Important things to consider before sending:")}
<ul class="list-advice">
<li class="item">${_("Have you read over the email to make sure it says everything you want to say?")}</li>
<li class="item">${_("Have you sent the email to yourself first to make sure you're happy with how it's displayed?")}</li>
</ul>
<input type="submit" name="send-email" value="Send email" data-endpoint="${ section_data[get_send_email_url']}">
</div>
</form>
\ No newline at end of file
......@@ -31,6 +31,12 @@
<script type="text/javascript" src="${static.url('js/vendor/slick.grid.js')}"></script>
<link rel="stylesheet" href="${static.url('css/vendor/slickgrid/smoothness/jquery-ui-1.8.16.custom.css')}">
<link rel="stylesheet" href="${static.url('css/vendor/slickgrid/slick.grid.css')}">
<script type="text/javascript" src="${static.url('js/vendor/CodeMirror/htmlmixed.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/CodeMirror/css.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/codemirror-compressed.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/tiny_mce/tiny_mce.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/tiny_mce/jquery.tinymce.js')}"></script>
<%static:js group='module-descriptor-js'/>
</%block>
## NOTE that instructor is set as the active page so that the instructor button lights up, even though this is the instructor_2 page.
......
<%! from django.utils.translation import ugettext as _ %>
<%page args="section_data"/>
<script language="JavaScript" type="text/javascript">
</script>
<div class="vert-left send-email">
<h2> ${_("Send Email")} </h2>
<label for="id_to">${_("Send to:")}</label>
<select id="id_to" name="send_to">
<option value="myself">${_("Myself")}</option>
%if to_option == "staff":
<option value="staff" selected="selected">${_("Staff and instructors")}</option>
%else:
<option value="staff">${_("Staff and instructors")}</option>
%endif
%if to_option == "all":
<option value="all" selected="selected">${_("All (students, staff and instructors)")}</option>
%else:
<option value="all">${_("All (students, staff and instructors)")}</option>
%endif
</select>
<br/>
<label for="id_subject">${_("Subject: ")}</label>
<input type="text" id="id_subject" name="subject">
<br/>
<label>Message:</label>
<div class="email-editor">
${ section_data['editor'] }
</div>
<input type="hidden" name="message" value="">
<br/>
<input type="button" name="send" value="${_("Send")}" data-endpoint="${ section_data['send_email'] }" >
<div class="request-response"></div>
<div class="request-response-error"></div>
</div>
\ No newline at end of file
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