From e325317bde00dc1189d88c4579cc651f7094d2ce Mon Sep 17 00:00:00 2001 From: Julia Hansbrough <julia@edx.org> Date: Fri, 4 Oct 2013 15:33:11 +0000 Subject: [PATCH] Changed GET to POST and xmodule HTML editor call, section CSS --- AUTHORS | 1 + CHANGELOG.rst | 2 + lms/djangoapps/instructor/tests/test_email.py | 1 - lms/djangoapps/instructor/views/api.py | 47 +++++++++++++-- .../instructor/views/instructor_dashboard.py | 6 +- lms/envs/dev.py | 1 + .../instructor_dashboard/send_email.coffee | 5 +- .../sass/course/instructor/_instructor_2.scss | 58 +++++++++++++++++++ .../instructor_dashboard_2/send_email.html | 56 ++++++++++-------- 9 files changed, 144 insertions(+), 33 deletions(-) diff --git a/AUTHORS b/AUTHORS index 94963e46304..2f4d7efeadd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -89,3 +89,4 @@ Akshay Jagadeesh <akjags@gmail.com> Nick Parlante <nick.parlante@cs.stanford.edu> Marko Seric <marko.seric@math.uzh.ch> Felipe Montoya <felipe.montoya@edunext.co> +Julia Hansbrough <julia@edx.org> diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 952a0dfd9bc..f7891ae817b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,8 @@ the top. Include a label indicating the component affected. LMS: Disable data download buttons on the instructor dashboard for large courses +LMS: Ported bulk emailing to the beta instructor dashboard. + LMS: Refactor and clean student dashboard templates. LMS: Fix issue with CourseMode expiration dates diff --git a/lms/djangoapps/instructor/tests/test_email.py b/lms/djangoapps/instructor/tests/test_email.py index 5f664bc0e5f..1150c575fed 100644 --- a/lms/djangoapps/instructor/tests/test_email.py +++ b/lms/djangoapps/instructor/tests/test_email.py @@ -53,7 +53,6 @@ class TestInstructorDashboardEmailView(ModuleStoreTestCase): @patch.dict(settings.MITX_FEATURES, {'ENABLE_INSTRUCTOR_EMAIL': True}) def test_email_flag_true(self): - from nose.tools import set_trace; set_trace() # Assert that the URL for the email view is in the response response = self.client.get(self.url) self.assertTrue(self.email_link in response.content) diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index 25e070d01a2..e7f394cea15 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -106,6 +106,43 @@ def require_query_params(*args, **kwargs): return wrapped return decorator +def require_post_params(*args, **kwargs): + """ + Checks for required paremters or renders a 400 error. + (decorator with arguments) + + `args` is a *list of required GET parameter names. + `kwargs` is a **dict of required GET parameter names + to string explanations of the parameter + """ + required_params = [] + required_params += [(arg, None) for arg in args] + required_params += [(key, kwargs[key]) for key in kwargs] + # required_params = e.g. [('action', 'enroll or unenroll'), ['emails', None]] + + def decorator(func): # pylint: disable=C0111 + def wrapped(*args, **kwargs): # pylint: disable=C0111 + request = args[0] + + error_response_data = { + 'error': 'Missing required query parameter(s)', + 'parameters': [], + 'info': {}, + } + + for (param, extra) in required_params: + default = object() + if request.POST.get(param, default) == default: + error_response_data['parameters'] += [param] + error_response_data['info'][param] = extra + + if len(error_response_data['parameters']) > 0: + return JsonResponse(error_response_data, status=400) + else: + return func(*args, **kwargs) + return wrapped + return decorator + def require_level(level): """ @@ -749,19 +786,19 @@ def send_email(request, course_id): @ensure_csrf_cookie @cache_control(no_cache=True, no_store=True, must_revalidate=True) @require_level('staff') -@require_query_params(send_to="sending to whom", subject="subject line", message="message text") +@require_post_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: + Query Parameters: - 'send_to' specifies what group the email should be sent to - 'subject' specifies email's subject - 'message' specifies email's content """ course = get_course_by_id(course_id) - send_to = request.GET.get("send_to") - subject = request.GET.get("subject") - message = request.GET.get("message") + send_to = request.POST.get("send_to") + subject = request.POST.get("subject") + message = request.POST.get("message") text_message = html_to_text(message) email = CourseEmail( course_id=course_id, diff --git a/lms/djangoapps/instructor/views/instructor_dashboard.py b/lms/djangoapps/instructor/views/instructor_dashboard.py index 4c24e0e4286..4bdce87f4e0 100644 --- a/lms/djangoapps/instructor/views/instructor_dashboard.py +++ b/lms/djangoapps/instructor/views/instructor_dashboard.py @@ -138,6 +138,7 @@ def _section_student_admin(course_id, access): 'section_display_name': _('Student Admin'), 'access': access, 'get_student_progress_url_url': reverse('get_student_progress_url', kwargs={'course_id': course_id}), + 'enrollment_url': reverse('students_update_enrollment', kwargs={'course_id': course_id}), 'reset_student_attempts_url': reverse('reset_student_attempts', kwargs={'course_id': course_id}), 'rescore_problem_url': reverse('rescore_problem', kwargs={'course_id': course_id}), 'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': course_id}), @@ -160,12 +161,15 @@ def _section_data_download(course_id): 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)) + fragment = course.system.render(html_module, None, 'studio_view') + fragment = wrap_xmodule('xmodule_edit.html', html_module, 'studio_view', fragment, None) + email_editor = fragment.content 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')() + 'editor': email_editor } return section_data diff --git a/lms/envs/dev.py b/lms/envs/dev.py index 4d46dc52e2d..e873861196d 100644 --- a/lms/envs/dev.py +++ b/lms/envs/dev.py @@ -29,6 +29,7 @@ MITX_FEATURES['ENABLE_MANUAL_GIT_RELOAD'] = True MITX_FEATURES['ENABLE_PSYCHOMETRICS'] = False # real-time psychometrics (eg item response theory analysis in instructor dashboard) MITX_FEATURES['ENABLE_INSTRUCTOR_ANALYTICS'] = True MITX_FEATURES['ENABLE_SERVICE_STATUS'] = True +MITX_FEATURES['ENABLE_INSTRUCTOR_EMAIL'] = True MITX_FEATURES['ENABLE_HINTER_INSTRUCTOR_VIEW'] = True MITX_FEATURES['ENABLE_INSTRUCTOR_BETA_DASHBOARD'] = True MITX_FEATURES['MULTIPLE_ENROLLMENT_ROLES'] = True diff --git a/lms/static/coffee/src/instructor_dashboard/send_email.coffee b/lms/static/coffee/src/instructor_dashboard/send_email.coffee index af509a7d525..c8b0588b5d9 100644 --- a/lms/static/coffee/src/instructor_dashboard/send_email.coffee +++ b/lms/static/coffee/src/instructor_dashboard/send_email.coffee @@ -22,6 +22,8 @@ class SendEmail # attach click handlers @$btn_send.click => + + success_message = gettext('Your email was successfully queued for sending.') send_data = action: 'send' @@ -30,10 +32,11 @@ class SendEmail message: @$emailEditor.save()['data'] $.ajax + type: 'POST' dataType: 'json' url: @$btn_send.data 'endpoint' data: send_data - success: (data) => @display_response gettext('Your email was successfully queued for sending.') + success: (data) => @display_response ("<div class=\"msg msg-confirm\"><p class=\"copy\">" + success_message + "</p></div>") error: std_ajax_err => @fail_with_error gettext('Error sending email.') fail_with_error: (msg) -> diff --git a/lms/static/sass/course/instructor/_instructor_2.scss b/lms/static/sass/course/instructor/_instructor_2.scss index 19f6abf5ed7..c9a4c79aa8f 100644 --- a/lms/static/sass/course/instructor/_instructor_2.scss +++ b/lms/static/sass/course/instructor/_instructor_2.scss @@ -241,6 +241,60 @@ section.instructor-dashboard-content-2 { } } +.instructor-dashboard-wrapper-2 section.idash-section#send_email { + // form fields + .list-fields { + list-style: none; + margin: 0; + padding: 0; + + .field { + margin-bottom: 20px; + padding: 0; + + &:last-child { + margin-bottom: 0; + } + } + } + + // system feedback - messages + .msg { + + + .copy { + font-weight: 600; + } + } + + .msg-confirm { + background: tint(green,90%); + + .copy { + color: green; + } + } + + .list-advice { + list-style: none; + padding: 0; + margin: 20px 0; + + .item { + font-weight: 600; + margin-bottom: 10px; + + &:last-child { + margin-bottom: 0; + } + } + } + .msg .copy { + font-weight: 600; } + .msg-confirm { + background: #e5f2e5; } +} + .instructor-dashboard-wrapper-2 section.idash-section#membership { $half_width: $baseline * 20; @@ -538,3 +592,7 @@ section.instructor-dashboard-content-2 { right: $baseline; } } + +input[name="subject"] { + width:600px; +} diff --git a/lms/templates/instructor/instructor_dashboard_2/send_email.html b/lms/templates/instructor/instructor_dashboard_2/send_email.html index 68fd0938a17..5a11bcf2073 100644 --- a/lms/templates/instructor/instructor_dashboard_2/send_email.html +++ b/lms/templates/instructor/instructor_dashboard_2/send_email.html @@ -6,38 +6,44 @@ <script type="text/javascript" src="jsi18n/"></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: + <div class="request-response msg msg-confirm"></div> + <ul class="list-fields"> + <li class="field"> + <label for="id_to">${_("Send to:")}</label><br/> + <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=""> + %endif + </select> + </li> <br/> + <li class="field"> + <label for="id_subject">${_("Subject: ")}</label><br/> + <input type="text" id="id_subject" name="subject"> + </li> + <li class="field"> + <label>Message:</label> + <div class="email-editor"> + ${ section_data['editor'] } + </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. Before sending your email, consider:")} - <ul> + <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> </div> - <input type="button" name="send" value="${_("Send")}" data-endpoint="${ section_data['send_email'] }" > - <div class="request-response"></div> + <input type="button" name="send" value="${_("Send Email")}" data-endpoint="${ section_data['send_email'] }" > <div class="request-response-error"></div> </div> \ No newline at end of file -- GitLab