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
e6bde938
Commit
e6bde938
authored
Aug 22, 2013
by
Sarina Canelake
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Change bulk email model field names and add migrations
parent
b3bc4023
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
149 additions
and
37 deletions
+149
-37
common/lib/html_to_text.py
+3
-0
lms/djangoapps/bulk_email/migrations/0002_change_field_names.py
+94
-0
lms/djangoapps/bulk_email/models.py
+15
-3
lms/djangoapps/bulk_email/tasks.py
+12
-12
lms/djangoapps/bulk_email/tests/test_email.py
+7
-5
lms/djangoapps/instructor/views/legacy.py
+16
-15
lms/envs/aws.py
+1
-1
lms/templates/courseware/instructor_dashboard.html
+1
-1
No files found.
common/lib/html_to_text.py
View file @
e6bde938
"""Provides a function to convert html to plaintext."""
import
logging
from
subprocess
import
Popen
,
PIPE
log
=
logging
.
getLogger
(
__name__
)
def
html_to_text
(
html_message
):
"""
Converts an html message to plaintext.
...
...
lms/djangoapps/bulk_email/migrations/0002_change_field_names.py
0 → 100644
View file @
e6bde938
# -*- coding: utf-8 -*-
import
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Renaming field 'CourseEmail.to'
db
.
rename_column
(
'bulk_email_courseemail'
,
'to'
,
'to_option'
)
# Renaming field 'CourseEmail.hash'
db
.
rename_column
(
'bulk_email_courseemail'
,
'hash'
,
'slug'
)
# Adding field 'CourseEmail.text_message'
db
.
add_column
(
'bulk_email_courseemail'
,
'text_message'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
null
=
True
,
blank
=
True
),
keep_default
=
False
)
def
backwards
(
self
,
orm
):
# Renaming field 'CourseEmail.to_option'
db
.
rename_column
(
'bulk_email_courseemail'
,
'to_option'
,
'to'
)
# Renaming field 'CourseEmail.slug'
db
.
rename_column
(
'bulk_email_courseemail'
,
'slug'
,
'hash'
)
# Deleting field 'CourseEmail.text_message'
db
.
delete_column
(
'bulk_email_courseemail'
,
'text_message'
)
models
=
{
'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"('content_type__app_label', 'content_type__model', 'codename')"
,
'unique_together'
:
"(('content_type', 'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['contenttypes.ContentType']"
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Group']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
})
},
'bulk_email.courseemail'
:
{
'Meta'
:
{
'object_name'
:
'CourseEmail'
},
'course_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'created'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'html_message'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'modified'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'sender'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'default'
:
'1'
,
'to'
:
"orm['auth.User']"
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'slug'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
,
'db_index'
:
'True'
}),
'subject'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
,
'blank'
:
'True'
}),
'text_message'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'to_option'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'myself'"
,
'max_length'
:
'64'
})
},
'bulk_email.optout'
:
{
'Meta'
:
{
'unique_together'
:
"(('email', 'course_id'),)"
,
'object_name'
:
'Optout'
},
'course_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'email'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
})
},
'contenttypes.contenttype'
:
{
'Meta'
:
{
'ordering'
:
"('name',)"
,
'unique_together'
:
"(('app_label', 'model'),)"
,
'object_name'
:
'ContentType'
,
'db_table'
:
"'django_content_type'"
},
'app_label'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'model'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
})
}
}
complete_apps
=
[
'bulk_email'
]
lms/djangoapps/bulk_email/models.py
View file @
e6bde938
"""
Models for bulk email
WE'RE USING MIGRATIONS!
If you make changes to this model, be sure to create an appropriate migration
file and check it in at the same time as your model changes. To do that,
1. Go to the edx-platform dir
2. ./manage.py lms schemamigration bulk_email --auto description_of_your_change
3. Add the migration file created in edx-platform/lms/djangoapps/bulk_email/migrations/
ASSUMPTIONS: modules have unique IDs, even across different module_types
"""
from
django.db
import
models
from
django.contrib.auth.models
import
User
...
...
@@ -10,8 +23,7 @@ class Email(models.Model):
Abstract base class for common information for an email.
"""
sender
=
models
.
ForeignKey
(
User
,
default
=
1
,
blank
=
True
,
null
=
True
)
# The unique hash for this email. Used to quickly look up an email (see `tasks.py`)
hash
=
models
.
CharField
(
max_length
=
128
,
db_index
=
True
)
slug
=
models
.
CharField
(
max_length
=
128
,
db_index
=
True
)
subject
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
)
html_message
=
models
.
TextField
(
null
=
True
,
blank
=
True
)
text_message
=
models
.
TextField
(
null
=
True
,
blank
=
True
)
...
...
@@ -41,7 +53,7 @@ class CourseEmail(Email, models.Model):
(
'all'
,
'All'
)
)
course_id
=
models
.
CharField
(
max_length
=
255
,
db_index
=
True
)
to
=
models
.
CharField
(
max_length
=
64
,
choices
=
TO_OPTIONS
,
default
=
'myself'
)
to
_option
=
models
.
CharField
(
max_length
=
64
,
choices
=
TO_OPTIONS
,
default
=
'myself'
)
def
__unicode__
(
self
):
return
self
.
subject
...
...
lms/djangoapps/bulk_email/tasks.py
View file @
e6bde938
...
...
@@ -24,7 +24,7 @@ log = logging.getLogger(__name__)
@task
(
default_retry_delay
=
10
,
max_retries
=
5
)
# pylint: disable=E1102
def
delegate_email_batches
(
hash_for_msg
,
to_option
,
course_id
,
course_url
,
user_id
):
def
delegate_email_batches
(
email_id
,
to_option
,
course_id
,
course_url
,
user_id
):
"""
Delegates emails by querying for the list of recipients who should
get the mail, chopping up into batches of settings.EMAILS_PER_TASK size,
...
...
@@ -37,14 +37,14 @@ def delegate_email_batches(hash_for_msg, to_option, course_id, course_url, user_
try
:
course
=
get_course_by_id
(
course_id
)
except
Http404
as
exc
:
log
.
error
(
"get_course_by_id failed:
"
+
exc
.
args
[
0
])
log
.
error
(
"get_course_by_id failed:
%
s"
,
exc
.
args
[
0
])
raise
Exception
(
"get_course_by_id failed: "
+
exc
.
args
[
0
])
try
:
CourseEmail
.
objects
.
get
(
hash
=
hash_for_msg
)
CourseEmail
.
objects
.
get
(
id
=
email_id
)
except
CourseEmail
.
DoesNotExist
as
exc
:
log
.
warning
(
"Failed to get CourseEmail with
hash
%
s, retry
%
d"
,
hash_for_msg
,
current_task
.
request
.
retries
)
raise
delegate_email_batches
.
retry
(
arg
=
[
hash_for_msg
,
to_option
,
course_id
,
course_url
,
user_id
],
exc
=
exc
)
log
.
warning
(
"Failed to get CourseEmail with
id
%
s, retry
%
d"
,
email_id
,
current_task
.
request
.
retries
)
raise
delegate_email_batches
.
retry
(
arg
=
[
email_id
,
to_option
,
course_id
,
course_url
,
user_id
],
exc
=
exc
)
if
to_option
==
"myself"
:
recipient_qset
=
User
.
objects
.
filter
(
id
=
user_id
)
.
values
(
'profile__name'
,
'email'
)
...
...
@@ -77,12 +77,12 @@ def delegate_email_batches(hash_for_msg, to_option, course_id, course_url, user_
for
i
in
range
(
num_workers
):
to_list
=
recipient_list
[
i
*
chunk
:
i
*
chunk
+
chunk
]
course_email
.
delay
(
hash_for_msg
,
to_list
,
course
.
display_name
,
course_url
,
False
)
course_email
.
delay
(
email_id
,
to_list
,
course
.
display_name
,
course_url
,
False
)
return
num_workers
@task
(
default_retry_delay
=
15
,
max_retries
=
5
)
# pylint: disable=E1102
def
course_email
(
hash_for_msg
,
to_list
,
course_title
,
course_url
,
throttle
=
False
):
def
course_email
(
email_id
,
to_list
,
course_title
,
course_url
,
throttle
=
False
):
"""
Takes a subject and an html formatted email and sends it from
sender to all addresses in the to_list, with each recipient
...
...
@@ -90,7 +90,7 @@ def course_email(hash_for_msg, to_list, course_title, course_url, throttle=False
text and html.
"""
try
:
msg
=
CourseEmail
.
objects
.
get
(
hash
=
hash_for_msg
)
msg
=
CourseEmail
.
objects
.
get
(
id
=
email_id
)
except
CourseEmail
.
DoesNotExist
as
exc
:
log
.
exception
(
exc
.
args
[
0
])
raise
exc
...
...
@@ -112,6 +112,7 @@ def course_email(hash_for_msg, to_list, course_title, course_url, throttle=False
'course_title'
:
course_title
,
'course_url'
:
course_url
}
while
to_list
:
(
name
,
email
)
=
to_list
[
-
1
]
.
values
()
email_context
[
'name'
]
=
name
...
...
@@ -126,7 +127,6 @@ def course_email(hash_for_msg, to_list, course_title, course_url, throttle=False
'emails/email_footer.txt'
,
email_context
)
email_msg
=
EmailMultiAlternatives
(
subject
,
msg
.
text_message
+
plain_footer
.
encode
(
'utf-8'
),
...
...
@@ -142,7 +142,7 @@ def course_email(hash_for_msg, to_list, course_title, course_url, throttle=False
try
:
connection
.
send_messages
([
email_msg
])
log
.
info
(
'Email with
hash '
+
hash_for_msg
+
' sent to '
+
email
)
log
.
info
(
'Email with
id
%
s sent to
%
s'
,
email_id
,
email
)
num_sent
+=
1
except
SMTPDataError
as
exc
:
# According to SMTP spec, we'll retry error codes in the 4xx range. 5xx range indicates hard failure
...
...
@@ -151,7 +151,7 @@ def course_email(hash_for_msg, to_list, course_title, course_url, throttle=False
raise
exc
else
:
# This will fall through and not retry the message, since it will be popped
log
.
warning
(
'Email with
hash '
+
hash_for_msg
+
' not delivered to '
+
email
+
' due to error: '
+
exc
.
smtp_error
)
log
.
warning
(
'Email with
id
%
s not delivered to
%
s due to error
%
s'
,
email_id
,
email
,
exc
.
smtp_error
)
num_error
+=
1
to_list
.
pop
()
...
...
@@ -163,7 +163,7 @@ def course_email(hash_for_msg, to_list, course_title, course_url, throttle=False
# Error caught here cause the email to be retried. The entire task is actually retried without popping the list
raise
course_email
.
retry
(
arg
=
[
hash_for_msg
,
email_id
,
to_list
,
course_title
,
course_url
,
...
...
lms/djangoapps/bulk_email/tests/test_email.py
View file @
e6bde938
...
...
@@ -146,10 +146,11 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
# Now we know we have pulled up the instructor dash's email view
# (in the setUp method), we can test sending an email.
uni_subject
=
u'téśt śúbjéćt főŕ áĺĺ'
test_email
=
{
'action'
:
'Send email'
,
'to_option'
:
'all'
,
'subject'
:
u
'téśt śúbjéćt főŕ áĺĺ'
,
'subject'
:
u
ni_subject
,
'message'
:
'test message for all'
}
response
=
self
.
client
.
post
(
self
.
url
,
test_email
)
...
...
@@ -163,7 +164,7 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
)
self
.
assertEquals
(
mail
.
outbox
[
0
]
.
subject
,
'['
+
self
.
course
.
display_name
+
']
'
+
u' téśt śúbjéćt főŕ áĺĺ'
'['
+
self
.
course
.
display_name
+
']
'
+
uni_subject
)
def
test_unicode_message_send_to_all
(
self
):
...
...
@@ -173,11 +174,12 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
# Now we know we have pulled up the instructor dash's email view
# (in the setUp method), we can test sending an email.
uni_message
=
u'ẗëṡẗ ṁëṡṡäġë ḟöṛ äḷḷ イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ fоѓ аll'
test_email
=
{
'action'
:
'Send email'
,
'to_option'
:
'all'
,
'subject'
:
'test subject for all'
,
'message'
:
u
'ẗëṡẗ ṁëṡṡäġë ḟöṛ äḷḷ イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ fоѓ аll'
'message'
:
u
ni_message
}
response
=
self
.
client
.
post
(
self
.
url
,
test_email
)
...
...
@@ -190,7 +192,7 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
)
self
.
assertIn
(
u
'ẗëṡẗ ṁëṡṡäġë ḟöṛ äḷḷ イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ fоѓ аll'
,
u
ni_message
,
mail
.
outbox
[
0
]
.
body
)
...
...
@@ -238,4 +240,4 @@ class TestEmailSendExceptions(ModuleStoreTestCase):
def
test_no_course_email_obj
(
self
):
# Make sure course_email handles CourseEmail.DoesNotExist exception.
with
self
.
assertRaises
(
CourseEmail
.
DoesNotExist
):
course_email
(
"dummy hash"
,
[],
"_"
,
"_"
,
False
)
course_email
(
101
,
[],
"_"
,
"_"
,
False
)
lms/djangoapps/instructor/views/legacy.py
View file @
e6bde938
...
...
@@ -57,7 +57,6 @@ from mitxmako.shortcuts import render_to_string
from
bulk_email.models
import
CourseEmail
from
html_to_text
import
html_to_text
import
datetime
from
hashlib
import
md5
from
bulk_email
import
tasks
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -89,6 +88,7 @@ def instructor_dashboard(request, course_id):
to_option
=
None
subject
=
None
html_message
=
''
show_email_tab
=
False
problems
=
[]
plots
=
[]
datatable
=
{}
...
...
@@ -711,15 +711,16 @@ def instructor_dashboard(request, course_id):
email
=
CourseEmail
(
course_id
=
course_id
,
sender
=
request
.
user
,
to
=
to_option
,
to
_option
=
to_option
,
subject
=
subject
,
html_message
=
html_message
,
text_message
=
text_message
,
hash
=
md5
((
html_message
+
subject
+
datetime
.
datetime
.
isoformat
(
datetime
.
datetime
.
now
()))
.
encode
(
'utf-8'
))
.
hexdigest
())
text_message
=
text_message
)
email
.
save
()
course_url
=
request
.
build_absolute_uri
(
reverse
(
'course_root'
,
kwargs
=
{
'course_id'
:
course_id
}))
tasks
.
delegate_email_batches
.
delay
(
email
.
hash
,
email
.
to
,
course_id
,
course_url
,
request
.
user
.
id
)
tasks
.
delegate_email_batches
.
delay
(
email
.
id
,
email
.
to_option
,
course_id
,
course_url
,
request
.
user
.
id
)
if
to_option
==
"all"
:
email_msg
=
'<div class="msg msg-confirm"><p class="copy">Your email was successfully queued for sending. Please note that for large public classes (~10k), it may take 1-2 hours to send all emails.</p></div>'
...
...
@@ -798,11 +799,11 @@ def instructor_dashboard(request, course_id):
else
:
editor
=
None
# Flag for wh
at backing store this course is (Mongo vs. XML)
if
modulestore
()
.
get_modulestore_type
(
course_id
)
==
MONGO_MODULESTORE_TYPE
:
is_mongo_modulestore_type
=
True
else
:
is_mongo_modulestore_type
=
Fals
e
# Flag for wh
ether or not we display the email tab (depending upon
# what backing store this course using (Mongo vs. XML))
if
settings
.
MITX_FEATURES
[
'ENABLE_INSTRUCTOR_EMAIL'
]
and
\
modulestore
()
.
get_modulestore_type
(
course_id
)
==
MONGO_MODULESTORE_TYPE
:
show_email_tab
=
Tru
e
# display course stats only if there is no other table to display:
course_stats
=
None
...
...
@@ -820,10 +821,11 @@ def instructor_dashboard(request, course_id):
'course_stats'
:
course_stats
,
'msg'
:
msg
,
'modeflag'
:
{
idash_mode
:
'selectedmode'
},
'to_option'
:
to_option
,
# email
'subject'
:
subject
,
# email
'editor'
:
editor
,
# email
'email_msg'
:
email_msg
,
# email
'to_option'
:
to_option
,
# email
'subject'
:
subject
,
# email
'editor'
:
editor
,
# email
'email_msg'
:
email_msg
,
# email
'show_email_tab'
:
show_email_tab
,
# email
'problems'
:
problems
,
# psychometrics
'plots'
:
plots
,
# psychometrics
'course_errors'
:
modulestore
()
.
get_item_errors
(
course
.
location
),
...
...
@@ -832,7 +834,6 @@ def instructor_dashboard(request, course_id):
'cohorts_ajax_url'
:
reverse
(
'cohorts'
,
kwargs
=
{
'course_id'
:
course_id
}),
'analytics_results'
:
analytics_results
,
'is_mongo_modulestore_type'
:
is_mongo_modulestore_type
,
}
if
settings
.
MITX_FEATURES
.
get
(
'ENABLE_INSTRUCTOR_BETA_DASHBOARD'
):
...
...
lms/envs/aws.py
View file @
e6bde938
...
...
@@ -105,7 +105,7 @@ EMAIL_FILE_PATH = ENV_TOKENS.get('EMAIL_FILE_PATH', None)
EMAIL_HOST
=
ENV_TOKENS
.
get
(
'EMAIL_HOST'
,
'localhost'
)
# django default is localhost
EMAIL_PORT
=
ENV_TOKENS
.
get
(
'EMAIL_PORT'
,
25
)
# django default is 25
EMAIL_USE_TLS
=
ENV_TOKENS
.
get
(
'EMAIL_USE_TLS'
,
False
)
# django default is False
EMAILS_PER_TASK
=
ENV_TOKENS
.
get
(
'EMAILS_PER_TASK'
,
10
)
EMAILS_PER_TASK
=
ENV_TOKENS
.
get
(
'EMAILS_PER_TASK'
,
10
0
)
SITE_NAME
=
ENV_TOKENS
[
'SITE_NAME'
]
SESSION_ENGINE
=
ENV_TOKENS
.
get
(
'SESSION_ENGINE'
,
SESSION_ENGINE
)
...
...
lms/templates/courseware/instructor_dashboard.html
View file @
e6bde938
...
...
@@ -124,7 +124,7 @@ function goto( mode)
<a
href=
"#"
onclick=
"goto('Enrollment');"
class=
"${modeflag.get('Enrollment')}"
>
${_("Enrollment")}
</a>
|
<a
href=
"#"
onclick=
"goto('Data');"
class=
"${modeflag.get('Data')}"
>
${_("DataDump")}
</a>
|
<a
href=
"#"
onclick=
"goto('Manage Groups');"
class=
"${modeflag.get('Manage Groups')}"
>
${_("Manage Groups")}
</a>
%if s
ettings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_EMAIL') and is_mongo_modulestore_type
:
%if s
how_email_tab
:
|
<a
href=
"#"
onclick=
"goto('Email')"
class=
"${modeflag.get('Email')}"
>
Email
</a>
%endif
%if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_ANALYTICS'):
...
...
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