Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
91c31e12
Commit
91c31e12
authored
Oct 03, 2013
by
Julia Hansbrough
Committed by
Brian Wilson
Oct 16, 2013
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implemented bulk email interface for new dashboard
parent
014089e6
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
254 additions
and
6 deletions
+254
-6
lms/djangoapps/instructor/views/api.py
+45
-1
lms/djangoapps/instructor/views/api_urls.py
+2
-1
lms/djangoapps/instructor/views/instructor_dashboard.py
+18
-2
lms/djangoapps/instructor/views/legacy.py
+0
-1
lms/envs/common.py
+1
-1
lms/static/coffee/src/instructor_dashboard/instructor_dashboard.coffee
+3
-0
lms/static/coffee/src/instructor_dashboard/send_email.coffee
+73
-0
lms/static/sass/course/instructor/_instructor_2.scss
+4
-0
lms/templates/instructor/instructor_dashboard_2/email.html
+66
-0
lms/templates/instructor/instructor_dashboard_2/instructor_dashboard_2.html
+6
-0
lms/templates/instructor/instructor_dashboard_2/send_email.html
+36
-0
No files found.
lms/djangoapps/instructor/views/api.py
View file @
91c31e12
...
@@ -40,6 +40,12 @@ import analytics.distributions
...
@@ -40,6 +40,12 @@ import analytics.distributions
import
analytics.csvs
import
analytics.csvs
import
csv
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__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -705,6 +711,45 @@ def list_forum_members(request, course_id):
...
@@ -705,6 +711,45 @@ def list_forum_members(request, course_id):
}
}
return
JsonResponse
(
response_payload
)
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
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
...
@@ -769,7 +814,6 @@ def update_forum_role_membership(request, course_id):
...
@@ -769,7 +814,6 @@ def update_forum_role_membership(request, course_id):
}
}
return
JsonResponse
(
response_payload
)
return
JsonResponse
(
response_payload
)
@ensure_csrf_cookie
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@require_level
(
'staff'
)
@require_level
(
'staff'
)
...
...
lms/djangoapps/instructor/views/api_urls.py
View file @
91c31e12
...
@@ -2,7 +2,6 @@
...
@@ -2,7 +2,6 @@
Instructor API endpoint urls.
Instructor API endpoint urls.
"""
"""
from
django.conf.urls
import
patterns
,
url
from
django.conf.urls
import
patterns
,
url
urlpatterns
=
patterns
(
''
,
# nopep8
urlpatterns
=
patterns
(
''
,
# nopep8
...
@@ -34,4 +33,6 @@ urlpatterns = patterns('', # nopep8
...
@@ -34,4 +33,6 @@ urlpatterns = patterns('', # nopep8
'instructor.views.api.update_forum_role_membership'
,
name
=
"update_forum_role_membership"
),
'instructor.views.api.update_forum_role_membership'
,
name
=
"update_forum_role_membership"
),
url
(
r'^proxy_legacy_analytics$'
,
url
(
r'^proxy_legacy_analytics$'
,
'instructor.views.api.proxy_legacy_analytics'
,
name
=
"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"
)
)
)
lms/djangoapps/instructor/views/instructor_dashboard.py
View file @
91c31e12
...
@@ -10,6 +10,10 @@ from django.core.urlresolvers import reverse
...
@@ -10,6 +10,10 @@ from django.core.urlresolvers import reverse
from
django.utils.html
import
escape
from
django.utils.html
import
escape
from
django.http
import
Http404
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.access
import
has_access
from
courseware.courses
import
get_course_by_id
from
courseware.courses
import
get_course_by_id
from
django_comment_client.utils
import
has_forum_access
from
django_comment_client.utils
import
has_forum_access
...
@@ -17,7 +21,6 @@ from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR
...
@@ -17,7 +21,6 @@ from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
student.models
import
CourseEnrollment
from
student.models
import
CourseEnrollment
@ensure_csrf_cookie
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
def
instructor_dashboard_2
(
request
,
course_id
):
def
instructor_dashboard_2
(
request
,
course_id
):
...
@@ -42,7 +45,8 @@ def instructor_dashboard_2(request, course_id):
...
@@ -42,7 +45,8 @@ def instructor_dashboard_2(request, course_id):
_section_membership
(
course_id
,
access
),
_section_membership
(
course_id
,
access
),
_section_student_admin
(
course_id
,
access
),
_section_student_admin
(
course_id
,
access
),
_section_data_download
(
course_id
),
_section_data_download
(
course_id
),
_section_analytics
(
course_id
),
_section_send_email
(
course_id
,
access
,
course
),
_section_analytics
(
course_id
)
]
]
context
=
{
context
=
{
...
@@ -140,6 +144,18 @@ def _section_data_download(course_id):
...
@@ -140,6 +144,18 @@ def _section_data_download(course_id):
}
}
return
section_data
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
):
def
_section_analytics
(
course_id
):
""" Provide data for the corresponding dashboard section """
""" Provide data for the corresponding dashboard section """
...
...
lms/djangoapps/instructor/views/legacy.py
View file @
91c31e12
...
@@ -62,7 +62,6 @@ from bulk_email.models import CourseEmail
...
@@ -62,7 +62,6 @@ from bulk_email.models import CourseEmail
from
html_to_text
import
html_to_text
from
html_to_text
import
html_to_text
from
bulk_email
import
tasks
from
bulk_email
import
tasks
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
# internal commands for managing forum roles:
# internal commands for managing forum roles:
...
...
lms/envs/common.py
View file @
91c31e12
...
@@ -114,7 +114,7 @@ MITX_FEATURES = {
...
@@ -114,7 +114,7 @@ MITX_FEATURES = {
# analytics experiments
# analytics experiments
'ENABLE_INSTRUCTOR_ANALYTICS'
:
False
,
'ENABLE_INSTRUCTOR_ANALYTICS'
:
False
,
'ENABLE_INSTRUCTOR_EMAIL'
:
Fals
e
,
'ENABLE_INSTRUCTOR_EMAIL'
:
Tru
e
,
# enable analytics server.
# enable analytics server.
# WARNING: THIS SHOULD ALWAYS BE SET TO FALSE UNDER NORMAL
# WARNING: THIS SHOULD ALWAYS BE SET TO FALSE UNDER NORMAL
...
...
lms/static/coffee/src/instructor_dashboard/instructor_dashboard.coffee
View file @
91c31e12
...
@@ -157,6 +157,9 @@ setup_instructor_dashboard_sections = (idash_content) ->
...
@@ -157,6 +157,9 @@ setup_instructor_dashboard_sections = (idash_content) ->
constructor
:
window
.
InstructorDashboard
.
sections
.
StudentAdmin
constructor
:
window
.
InstructorDashboard
.
sections
.
StudentAdmin
$element
:
idash_content
.
find
".
#{
CSS_IDASH_SECTION
}
#student_admin"
$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
constructor
:
window
.
InstructorDashboard
.
sections
.
Analytics
$element
:
idash_content
.
find
".
#{
CSS_IDASH_SECTION
}
#analytics"
$element
:
idash_content
.
find
".
#{
CSS_IDASH_SECTION
}
#analytics"
]
]
...
...
lms/static/coffee/src/instructor_dashboard/send_email.coffee
0 → 100644
View file @
91c31e12
# 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
lms/static/sass/course/instructor/_instructor_2.scss
View file @
91c31e12
...
@@ -110,6 +110,10 @@ section.instructor-dashboard-content-2 {
...
@@ -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
{
.instructor-dashboard-wrapper-2
section
.idash-section
#course_info
{
.course-errors-wrapper
{
.course-errors-wrapper
{
...
...
lms/templates/instructor/instructor_dashboard_2/email.html
0 → 100644
View file @
91c31e12
<
%!
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"
>
<
p
>
hihihi
<
/p
>
</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
lms/templates/instructor/instructor_dashboard_2/instructor_dashboard_2.html
View file @
91c31e12
...
@@ -31,6 +31,12 @@
...
@@ -31,6 +31,12 @@
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/slick.grid.js')}"
></script>
<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/smoothness/jquery-ui-1.8.16.custom.css')}"
>
<link
rel=
"stylesheet"
href=
"${static.url('css/vendor/slickgrid/slick.grid.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>
</
%
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.
## NOTE that instructor is set as the active page so that the instructor button lights up, even though this is the instructor_2 page.
...
...
lms/templates/instructor/instructor_dashboard_2/send_email.html
0 → 100644
View file @
91c31e12
<
%!
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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment