Commit ed75b9b5 by Waheed Ahmed

Added publish button.

ECOM-6078
parent 5b2c8f3e
...@@ -672,3 +672,37 @@ class ChangeCourseRunStateViewTests(TestCase): ...@@ -672,3 +672,37 @@ class ChangeCourseRunStateViewTests(TestCase):
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual([course.publisher.email, course.project_coordinator.email], mail.outbox[0].bcc) self.assertEqual([course.publisher.email, course.project_coordinator.email], mail.outbox[0].bcc)
def test_course_published(self):
"""
Verify that publisher user can publish course run.
"""
course = self.course_run.course
self.run_state.name = CourseRunStateChoices.Approved
self.run_state.preview_accepted = True
self.run_state.save()
self._assign_role(course, PublisherUserRole.Publisher, self.user)
self._assign_role(course, PublisherUserRole.CourseTeam, UserFactory())
response = self.client.patch(
self.change_state_url,
data=json.dumps({'name': CourseRunStateChoices.Published}),
content_type=JSON_CONTENT_TYPE
)
self.assertEqual(response.status_code, 200)
self.run_state = CourseRunState.objects.get(course_run=self.course_run)
self.assertTrue(self.run_state.is_published)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual([course.course_team_admin.email], mail.outbox[0].to)
course_name = '{title}: {pacing_type} - {start_date}'.format(
title=course.title,
pacing_type=self.course_run.get_pacing_type_display(),
start_date=self.course_run.start.strftime("%B %d, %Y")
)
expected_subject = 'Course {course_name} is now live'.format(course_name=course_name)
self.assertEqual(str(mail.outbox[0].subject), expected_subject)
...@@ -372,3 +372,53 @@ def send_email_preview_page_is_available(course_run): ...@@ -372,3 +372,53 @@ def send_email_preview_page_is_available(course_run):
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
logger.exception('Failed to send email notifications for preview available of course-run %s', course_run.id) logger.exception('Failed to send email notifications for preview available of course-run %s', course_run.id)
def send_course_run_published_email(course_run):
""" Send course run published email.
Arguments:
course_run (Object): CourseRun object
"""
txt_template = 'publisher/email/course_run/published.txt'
html_template = 'publisher/email/course_run/published.html'
course_name = '{title}: {pacing_type} - {start_date}'.format(
title=course_run.course.title,
pacing_type=course_run.get_pacing_type_display(),
start_date=course_run.start.strftime("%B %d, %Y")
)
subject = _('Course {course_name} is now live').format(course_name=course_name) # pylint: disable=no-member
course_team_user = course_run.course.course_team_admin
try:
if is_email_notification_enabled(course_team_user):
to_addresses = [course_team_user.email]
from_address = settings.PUBLISHER_FROM_EMAIL
project_coordinator = course_run.course.project_coordinator
page_path = reverse('publisher:publisher_course_run_detail', kwargs={'pk': course_run.id})
context = {
'course_name': course_name,
'recipient_name': course_team_user.get_full_name() or course_team_user.username,
'contact_us_email': project_coordinator.email if project_coordinator else '',
'page_url': 'https://{host}{path}'.format(
host=Site.objects.get_current().domain.strip('/'), path=page_path
)
}
template = get_template(txt_template)
plain_content = template.render(context)
template = get_template(html_template)
html_content = template.render(context)
email_msg = EmailMultiAlternatives(
subject, plain_content, from_address, to=to_addresses
)
email_msg.attach_alternative(html_content, 'text/html')
email_msg.send()
except Exception: # pylint: disable=broad-except
error_message = 'Failed to send email notifications for course published of course-run [{run_id}]'.format(
run_id=course_run.id
)
logger.exception(error_message)
raise Exception(error_message)
...@@ -578,8 +578,7 @@ class CourseRunState(TimeStampedModel, ChangedByMixin): ...@@ -578,8 +578,7 @@ class CourseRunState(TimeStampedModel, ChangedByMixin):
@transition(field=name, source=CourseRunStateChoices.Approved, target=CourseRunStateChoices.Published) @transition(field=name, source=CourseRunStateChoices.Approved, target=CourseRunStateChoices.Published)
def published(self): def published(self):
# TODO: send email etc. emails.send_course_run_published_email(self.course_run)
pass
def change_state(self, state, user): def change_state(self, state, user):
if state == CourseRunStateChoices.Draft: if state == CourseRunStateChoices.Draft:
...@@ -627,6 +626,14 @@ class CourseRunState(TimeStampedModel, ChangedByMixin): ...@@ -627,6 +626,14 @@ class CourseRunState(TimeStampedModel, ChangedByMixin):
def is_approved(self): def is_approved(self):
return self.name == CourseRunStateChoices.Approved return self.name == CourseRunStateChoices.Approved
@property
def is_ready_to_publish(self):
return self.is_approved and self.is_preview_accepted
@property
def is_published(self):
return self.name == CourseRunStateChoices.Published
class PublisherUser(User): class PublisherUser(User):
""" Publisher User Proxy Model. """ """ Publisher User Proxy Model. """
......
...@@ -455,3 +455,58 @@ class CourseRunPreviewEmailTests(TestCase): ...@@ -455,3 +455,58 @@ class CourseRunPreviewEmailTests(TestCase):
) )
) )
) )
class CourseRunPublishedEmailTests(TestCase):
"""
Tests email functionality for course run published.
"""
def setUp(self):
super(CourseRunPublishedEmailTests, self).setUp()
self.user = UserFactory()
self.run_state = factories.CourseRunStateFactory()
self.course_run = self.run_state.course_run
self.course = self.course_run.course
# add users in CourseUserRole table
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.CourseTeam, user=self.user
)
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.Publisher, user=UserFactory()
)
toggle_switch('enable_publisher_email_notifications', True)
def test_course_published_email(self):
"""
Verify that course published email functionality works fine.
"""
emails.send_course_run_published_email(self.course_run)
course_name = '{title}: {pacing_type} - {start_date}'.format(
title=self.course.title,
pacing_type=self.course_run.get_pacing_type_display(),
start_date=self.course_run.start.strftime("%B %d, %Y")
)
subject = 'Course {course_name} is now live'.format(course_name=course_name)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual([self.course.course_team_admin.email], mail.outbox[0].to)
self.assertEqual(str(mail.outbox[0].subject), subject)
body = mail.outbox[0].body.strip()
page_path = reverse('publisher:publisher_course_run_detail', kwargs={'pk': self.course_run.id})
page_url = 'https://{host}{path}'.format(host=Site.objects.get_current().domain.strip('/'), path=page_path)
self.assertIn(page_url, body)
self.assertIn('is now live.', body)
def test_course_published_email_with_error(self):
""" Verify that email failure log error message."""
message = 'Failed to send email notifications for course published of course-run [{}]'.format(
self.course_run.id
)
with mock.patch('django.core.mail.message.EmailMessage.send', side_effect=TypeError):
with self.assertRaises(Exception) as ex:
emails.send_course_run_published_email(self.course_run)
self.assertEqual(str(ex.exception), message)
...@@ -546,6 +546,8 @@ class CourseRunStateTests(TestCase): ...@@ -546,6 +546,8 @@ class CourseRunStateTests(TestCase):
self.course.course_state.name = CourseStateChoices.Approved self.course.course_state.name = CourseStateChoices.Approved
self.course.save() self.course.save()
self.course_run.staff.add(PersonFactory()) self.course_run.staff.add(PersonFactory())
self.course_run_state.preview_accepted = False
self.course_run_state.save()
self.assertTrue(self.course_run_state.can_send_for_review()) self.assertTrue(self.course_run_state.can_send_for_review())
def test_str(self): def test_str(self):
...@@ -644,3 +646,22 @@ class CourseRunStateTests(TestCase): ...@@ -644,3 +646,22 @@ class CourseRunStateTests(TestCase):
self.course_run_state.name = CourseRunStateChoices.Approved self.course_run_state.name = CourseRunStateChoices.Approved
self.course_run_state.save() self.course_run_state.save()
self.assertTrue(self.course_run_state.is_approved) self.assertTrue(self.course_run_state.is_approved)
def test_is_ready_to_publish(self):
"""
Verify that method return is_ready_to_publish status.
"""
self.assertFalse(self.course_run_state.is_ready_to_publish)
self.course_run_state.name = CourseRunStateChoices.Approved
self.course_run_state.preview_accepted = True
self.course_run_state.save()
self.assertTrue(self.course_run_state.is_ready_to_publish)
def test_is_published(self):
"""
Verify that method return is_published status.
"""
self.assertFalse(self.course_run_state.is_published)
self.course_run_state.name = CourseRunStateChoices.Published
self.course_run_state.save()
self.assertTrue(self.course_run_state.is_published)
...@@ -1071,6 +1071,48 @@ class CourseRunDetailTests(TestCase): ...@@ -1071,6 +1071,48 @@ class CourseRunDetailTests(TestCase):
) )
self.assertContains(response, '<input id="id-review-url" type="text">') self.assertContains(response, '<input id="id-review-url" type="text">')
def test_course_publish_button(self):
"""Verify that publisher user can see Publish button."""
user_role = factories.CourseUserRoleFactory(
course=self.course, user=self.user, role=PublisherUserRole.Publisher
)
self.course_run_state.owner_role = PublisherUserRole.Publisher
self.course_run_state.name = CourseRunStateChoices.Approved
self.course_run_state.preview_accepted = True
self.course_run_state.save()
self.user.groups.add(self.organization_extension.group)
assign_perm(OrganizationExtension.VIEW_COURSE, self.organization_extension.group, self.organization_extension)
response = self.client.get(self.page_url)
self.assertContains(response, '<button class="btn-brand btn-base btn-publish"')
user_role.role = PublisherUserRole.CourseTeam
user_role.save()
response = self.client.get(self.page_url)
# Verify that course team user cannot se publish button.
self.assertNotContains(response, '<button class="btn-brand btn-base btn-publish"')
def test_course_published(self):
"""Verify that user can see Published status if course is published."""
self.course_run_state.name = CourseRunStateChoices.Published
self.course_run_state.preview_accepted = True
self.course_run_state.save()
self.user.groups.add(self.organization_extension.group)
assign_perm(OrganizationExtension.VIEW_COURSE, self.organization_extension.group, self.organization_extension)
response = self.client.get(self.page_url)
history_object = self.course_run_state.history.filter(
name=CourseRunStateChoices.Published
).order_by('-modified').first()
expected = 'Course run announced on {publish_date} - view it on edx.org at:'.format(
publish_date=history_object.modified.strftime('%m/%d/%y')
)
self.assertContains(response, expected)
self.assertNotContains(response, '<button class="btn-brand btn-base btn-publish"')
# pylint: disable=attribute-defined-outside-init # pylint: disable=attribute-defined-outside-init
@ddt.ddt @ddt.ddt
......
...@@ -139,6 +139,12 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.PublisherPermissionM ...@@ -139,6 +139,12 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.PublisherPermissionM
history_object = course_run_state.history.filter(preview_accepted=True).order_by('-modified').first() history_object = course_run_state.history.filter(preview_accepted=True).order_by('-modified').first()
if history_object: if history_object:
context['preview_accepted_date'] = history_object.modified context['preview_accepted_date'] = history_object.modified
if course_run_state.is_published:
history_object = course_run_state.history.filter(
name=CourseRunStateChoices.Published
).order_by('-modified').first()
if history_object:
context['publish_date'] = history_object.modified
context['breadcrumbs'] = make_bread_crumbs( context['breadcrumbs'] = make_bread_crumbs(
[ [
...@@ -157,6 +163,7 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.PublisherPermissionM ...@@ -157,6 +163,7 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.PublisherPermissionM
context['publisher_hide_features_for_pilot'] = waffle.switch_is_active('publisher_hide_features_for_pilot') context['publisher_hide_features_for_pilot'] = waffle.switch_is_active('publisher_hide_features_for_pilot')
context['publisher_comment_widget_feature'] = waffle.switch_is_active('publisher_comment_widget_feature') context['publisher_comment_widget_feature'] = waffle.switch_is_active('publisher_comment_widget_feature')
context['publisher_approval_widget_feature'] = waffle.switch_is_active('publisher_approval_widget_feature') context['publisher_approval_widget_feature'] = waffle.switch_is_active('publisher_approval_widget_feature')
context['publish_state_name'] = CourseRunStateChoices.Published
return context return context
......
...@@ -7,14 +7,14 @@ msgid "" ...@@ -7,14 +7,14 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-01 16:02+0500\n" "POT-Creation-Date: 2017-03-02 12:51+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: \n"
#: apps/api/filters.py #: apps/api/filters.py
#, python-brace-format #, python-brace-format
...@@ -511,6 +511,11 @@ msgstr "" ...@@ -511,6 +511,11 @@ msgstr ""
msgid "Preview for {run_name} is available" msgid "Preview for {run_name} is available"
msgstr "" msgstr ""
#: apps/publisher/emails.py
#, python-brace-format
msgid "Course {course_name} is now live"
msgstr ""
#: apps/publisher/forms.py #: apps/publisher/forms.py
msgid "Remove Image" msgid "Remove Image"
msgstr "" msgstr ""
...@@ -2022,6 +2027,12 @@ msgid "Course Run Detail" ...@@ -2022,6 +2027,12 @@ msgid "Course Run Detail"
msgstr "" msgstr ""
#: templates/publisher/course_run_detail.html #: templates/publisher/course_run_detail.html
#, python-format
msgid ""
"Course run announced on %(course_publish_date)s - view it on edx.org at:"
msgstr ""
#: templates/publisher/course_run_detail.html
msgid "All" msgid "All"
msgstr "" msgstr ""
...@@ -2345,6 +2356,10 @@ msgid "Accept" ...@@ -2345,6 +2356,10 @@ msgid "Accept"
msgstr "" msgstr ""
#: templates/publisher/course_run_detail/_widgets.html #: templates/publisher/course_run_detail/_widgets.html
msgid "Publish"
msgstr ""
#: templates/publisher/course_run_detail/_widgets.html
msgid "Submitted for review" msgid "Submitted for review"
msgstr "" msgstr ""
...@@ -2482,6 +2497,8 @@ msgstr "" ...@@ -2482,6 +2497,8 @@ msgstr ""
#: templates/publisher/email/course_run/preview_accepted.txt #: templates/publisher/email/course_run/preview_accepted.txt
#: templates/publisher/email/course_run/preview_available.html #: templates/publisher/email/course_run/preview_available.html
#: templates/publisher/email/course_run/preview_available.txt #: templates/publisher/email/course_run/preview_available.txt
#: templates/publisher/email/course_run/published.html
#: templates/publisher/email/course_run/published.txt
#: templates/publisher/email/decline_preview.html #: templates/publisher/email/decline_preview.html
#: templates/publisher/email/decline_preview.txt #: templates/publisher/email/decline_preview.txt
msgid "The edX team" msgid "The edX team"
...@@ -2515,6 +2532,8 @@ msgstr "" ...@@ -2515,6 +2532,8 @@ msgstr ""
#: templates/publisher/email/course/send_for_review.txt #: templates/publisher/email/course/send_for_review.txt
#: templates/publisher/email/course_run/mark_as_reviewed.html #: templates/publisher/email/course_run/mark_as_reviewed.html
#: templates/publisher/email/course_run/mark_as_reviewed.txt #: templates/publisher/email/course_run/mark_as_reviewed.txt
#: templates/publisher/email/course_run/published.html
#: templates/publisher/email/course_run/published.txt
#: templates/publisher/email/course_run/send_for_review.html #: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/course_run/send_for_review.txt #: templates/publisher/email/course_run/send_for_review.txt
#, python-format #, python-format
...@@ -2541,6 +2560,8 @@ msgstr "" ...@@ -2541,6 +2560,8 @@ msgstr ""
#: templates/publisher/email/course_run/preview_accepted.txt #: templates/publisher/email/course_run/preview_accepted.txt
#: templates/publisher/email/course_run/preview_available.html #: templates/publisher/email/course_run/preview_available.html
#: templates/publisher/email/course_run/preview_available.txt #: templates/publisher/email/course_run/preview_available.txt
#: templates/publisher/email/course_run/published.html
#: templates/publisher/email/course_run/published.txt
#: templates/publisher/email/course_run/send_for_review.html #: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/course_run/send_for_review.txt #: templates/publisher/email/course_run/send_for_review.txt
#: templates/publisher/email/studio_instance_created.html #: templates/publisher/email/studio_instance_created.html
...@@ -2555,6 +2576,7 @@ msgstr "" ...@@ -2555,6 +2576,7 @@ msgstr ""
#: templates/publisher/email/course_run/mark_as_reviewed.html #: templates/publisher/email/course_run/mark_as_reviewed.html
#: templates/publisher/email/course_run/preview_accepted.html #: templates/publisher/email/course_run/preview_accepted.html
#: templates/publisher/email/course_run/preview_available.html #: templates/publisher/email/course_run/preview_available.html
#: templates/publisher/email/course_run/published.html
#: templates/publisher/email/course_run/send_for_review.html #: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/studio_instance_created.html #: templates/publisher/email/studio_instance_created.html
#, python-format #, python-format
...@@ -2573,6 +2595,7 @@ msgstr "" ...@@ -2573,6 +2595,7 @@ msgstr ""
#: templates/publisher/email/course_run/mark_as_reviewed.txt #: templates/publisher/email/course_run/mark_as_reviewed.txt
#: templates/publisher/email/course_run/preview_accepted.txt #: templates/publisher/email/course_run/preview_accepted.txt
#: templates/publisher/email/course_run/preview_available.txt #: templates/publisher/email/course_run/preview_available.txt
#: templates/publisher/email/course_run/published.txt
#: templates/publisher/email/course_run/send_for_review.txt #: templates/publisher/email/course_run/send_for_review.txt
#: templates/publisher/email/studio_instance_created.txt #: templates/publisher/email/studio_instance_created.txt
#, python-format #, python-format
...@@ -2674,6 +2697,18 @@ msgstr "" ...@@ -2674,6 +2697,18 @@ msgstr ""
msgid "Preview for %(course_name)s is available for review. %(page_url)s" msgid "Preview for %(course_name)s is available for review. %(page_url)s"
msgstr "" msgstr ""
#: templates/publisher/email/course_run/published.html
#, python-format
msgid ""
"Your course %(link_start)s%(page_url)s%(link_middle)s %(course_name)s "
"%(link_end)s is now live."
msgstr ""
#: templates/publisher/email/course_run/published.txt
#, python-format
msgid "Your course %(course_name)s is now live. %(page_url)s"
msgstr ""
#: templates/publisher/email/course_run/send_for_review.html #: templates/publisher/email/course_run/send_for_review.html
#, python-format #, python-format
msgid "" msgid ""
......
...@@ -7,14 +7,14 @@ msgid "" ...@@ -7,14 +7,14 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-01 16:02+0500\n" "POT-Creation-Date: 2017-03-02 12:51+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: \n"
#: static/js/catalogs-change-form.js #: static/js/catalogs-change-form.js
msgid "Preview" msgid "Preview"
...@@ -33,6 +33,10 @@ msgid "Something went wrong!" ...@@ -33,6 +33,10 @@ msgid "Something went wrong!"
msgstr "" msgstr ""
#: static/js/publisher/publisher.js #: static/js/publisher/publisher.js
msgid "Something went wrong! please try again later."
msgstr ""
#: static/js/publisher/publisher.js
msgid "File must be smaller than 1 megabyte in size." msgid "File must be smaller than 1 megabyte in size."
msgstr "" msgstr ""
......
...@@ -7,14 +7,14 @@ msgid "" ...@@ -7,14 +7,14 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-01 16:02+0500\n" "POT-Creation-Date: 2017-03-02 12:51+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: apps/api/filters.py #: apps/api/filters.py
...@@ -633,6 +633,11 @@ msgid "Preview for {run_name} is available" ...@@ -633,6 +633,11 @@ msgid "Preview for {run_name} is available"
msgstr "" msgstr ""
"Prévïéw för {run_name} ïs äväïläßlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" "Prévïéw för {run_name} ïs äväïläßlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#"
#: apps/publisher/emails.py
#, python-brace-format
msgid "Course {course_name} is now live"
msgstr "Çöürsé {course_name} ïs nöw lïvé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#"
#: apps/publisher/forms.py #: apps/publisher/forms.py
msgid "Remove Image" msgid "Remove Image"
msgstr "Rémövé Ìmägé Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" msgstr "Rémövé Ìmägé Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#"
...@@ -2470,6 +2475,14 @@ msgid "Course Run Detail" ...@@ -2470,6 +2475,14 @@ msgid "Course Run Detail"
msgstr "Çöürsé Rün Détäïl Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" msgstr "Çöürsé Rün Détäïl Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#"
#: templates/publisher/course_run_detail.html #: templates/publisher/course_run_detail.html
#, python-format
msgid ""
"Course run announced on %(course_publish_date)s - view it on edx.org at:"
msgstr ""
"Çöürsé rün ännöünçéd ön %(course_publish_date)s - vïéw ït ön édx.örg ät: "
"Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
#: templates/publisher/course_run_detail.html
msgid "All" msgid "All"
msgstr "Àll Ⱡ'σяєм#" msgstr "Àll Ⱡ'σяєм#"
...@@ -2801,6 +2814,10 @@ msgid "Accept" ...@@ -2801,6 +2814,10 @@ msgid "Accept"
msgstr "Àççépt Ⱡ'σяєм ιρѕυ#" msgstr "Àççépt Ⱡ'σяєм ιρѕυ#"
#: templates/publisher/course_run_detail/_widgets.html #: templates/publisher/course_run_detail/_widgets.html
msgid "Publish"
msgstr "Püßlïsh Ⱡ'σяєм ιρѕυм #"
#: templates/publisher/course_run_detail/_widgets.html
msgid "Submitted for review" msgid "Submitted for review"
msgstr "Süßmïttéd för révïéw Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" msgstr "Süßmïttéd för révïéw Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
...@@ -2957,6 +2974,8 @@ msgstr "Vïéw Çöürsé Ⱡ'σяєм ιρѕυм ∂σłσя #" ...@@ -2957,6 +2974,8 @@ msgstr "Vïéw Çöürsé Ⱡ'σяєм ιρѕυм ∂σłσя #"
#: templates/publisher/email/course_run/preview_accepted.txt #: templates/publisher/email/course_run/preview_accepted.txt
#: templates/publisher/email/course_run/preview_available.html #: templates/publisher/email/course_run/preview_available.html
#: templates/publisher/email/course_run/preview_available.txt #: templates/publisher/email/course_run/preview_available.txt
#: templates/publisher/email/course_run/published.html
#: templates/publisher/email/course_run/published.txt
#: templates/publisher/email/decline_preview.html #: templates/publisher/email/decline_preview.html
#: templates/publisher/email/decline_preview.txt #: templates/publisher/email/decline_preview.txt
msgid "The edX team" msgid "The edX team"
...@@ -2992,6 +3011,8 @@ msgstr "Vïéw çömmént: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" ...@@ -2992,6 +3011,8 @@ msgstr "Vïéw çömmént: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#"
#: templates/publisher/email/course/send_for_review.txt #: templates/publisher/email/course/send_for_review.txt
#: templates/publisher/email/course_run/mark_as_reviewed.html #: templates/publisher/email/course_run/mark_as_reviewed.html
#: templates/publisher/email/course_run/mark_as_reviewed.txt #: templates/publisher/email/course_run/mark_as_reviewed.txt
#: templates/publisher/email/course_run/published.html
#: templates/publisher/email/course_run/published.txt
#: templates/publisher/email/course_run/send_for_review.html #: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/course_run/send_for_review.txt #: templates/publisher/email/course_run/send_for_review.txt
#, python-format #, python-format
...@@ -3020,6 +3041,8 @@ msgstr "" ...@@ -3020,6 +3041,8 @@ msgstr ""
#: templates/publisher/email/course_run/preview_accepted.txt #: templates/publisher/email/course_run/preview_accepted.txt
#: templates/publisher/email/course_run/preview_available.html #: templates/publisher/email/course_run/preview_available.html
#: templates/publisher/email/course_run/preview_available.txt #: templates/publisher/email/course_run/preview_available.txt
#: templates/publisher/email/course_run/published.html
#: templates/publisher/email/course_run/published.txt
#: templates/publisher/email/course_run/send_for_review.html #: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/course_run/send_for_review.txt #: templates/publisher/email/course_run/send_for_review.txt
#: templates/publisher/email/studio_instance_created.html #: templates/publisher/email/studio_instance_created.html
...@@ -3034,6 +3057,7 @@ msgstr "Thänks, Ⱡ'σяєм ιρѕυм #" ...@@ -3034,6 +3057,7 @@ msgstr "Thänks, Ⱡ'σяєм ιρѕυм #"
#: templates/publisher/email/course_run/mark_as_reviewed.html #: templates/publisher/email/course_run/mark_as_reviewed.html
#: templates/publisher/email/course_run/preview_accepted.html #: templates/publisher/email/course_run/preview_accepted.html
#: templates/publisher/email/course_run/preview_available.html #: templates/publisher/email/course_run/preview_available.html
#: templates/publisher/email/course_run/published.html
#: templates/publisher/email/course_run/send_for_review.html #: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/studio_instance_created.html #: templates/publisher/email/studio_instance_created.html
#, python-format #, python-format
...@@ -3056,6 +3080,7 @@ msgstr "" ...@@ -3056,6 +3080,7 @@ msgstr ""
#: templates/publisher/email/course_run/mark_as_reviewed.txt #: templates/publisher/email/course_run/mark_as_reviewed.txt
#: templates/publisher/email/course_run/preview_accepted.txt #: templates/publisher/email/course_run/preview_accepted.txt
#: templates/publisher/email/course_run/preview_available.txt #: templates/publisher/email/course_run/preview_available.txt
#: templates/publisher/email/course_run/published.txt
#: templates/publisher/email/course_run/send_for_review.txt #: templates/publisher/email/course_run/send_for_review.txt
#: templates/publisher/email/studio_instance_created.txt #: templates/publisher/email/studio_instance_created.txt
#, python-format #, python-format
...@@ -3196,6 +3221,22 @@ msgstr "" ...@@ -3196,6 +3221,22 @@ msgstr ""
"Prévïéw för %(course_name)s ïs äväïläßlé för révïéw. %(page_url)s Ⱡ'σяєм " "Prévïéw för %(course_name)s ïs äväïläßlé för révïéw. %(page_url)s Ⱡ'σяєм "
"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" "ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #"
#: templates/publisher/email/course_run/published.html
#, python-format
msgid ""
"Your course %(link_start)s%(page_url)s%(link_middle)s %(course_name)s "
"%(link_end)s is now live."
msgstr ""
"Ýöür çöürsé %(link_start)s%(page_url)s%(link_middle)s %(course_name)s "
"%(link_end)s ïs nöw lïvé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #"
#: templates/publisher/email/course_run/published.txt
#, python-format
msgid "Your course %(course_name)s is now live. %(page_url)s"
msgstr ""
"Ýöür çöürsé %(course_name)s ïs nöw lïvé. %(page_url)s Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт"
" αмєт, ¢σηѕє¢тє#"
#: templates/publisher/email/course_run/send_for_review.html #: templates/publisher/email/course_run/send_for_review.html
#, python-format #, python-format
msgid "" msgid ""
......
...@@ -7,14 +7,14 @@ msgid "" ...@@ -7,14 +7,14 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-01 16:02+0500\n" "POT-Creation-Date: 2017-03-02 12:51+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/js/catalogs-change-form.js #: static/js/catalogs-change-form.js
...@@ -34,6 +34,12 @@ msgid "Something went wrong!" ...@@ -34,6 +34,12 @@ msgid "Something went wrong!"
msgstr "Söméthïng wént wröng! Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" msgstr "Söméthïng wént wröng! Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
#: static/js/publisher/publisher.js #: static/js/publisher/publisher.js
msgid "Something went wrong! please try again later."
msgstr ""
"Söméthïng wént wröng! pléäsé trý ägäïn lätér. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
"¢σηѕє¢тєтυя #"
#: static/js/publisher/publisher.js
msgid "File must be smaller than 1 megabyte in size." msgid "File must be smaller than 1 megabyte in size."
msgstr "" msgstr ""
"Fïlé müst ßé smällér thän 1 mégäßýté ïn sïzé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "Fïlé müst ßé smällér thän 1 mégäßýté ïn sïzé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
......
...@@ -132,7 +132,7 @@ $(document).ready(function(){ ...@@ -132,7 +132,7 @@ $(document).ready(function(){
}); });
$('.btn-change-state').click(function (e) { $('.btn-change-state, .btn-publish').click(function (e) {
$.ajax({ $.ajax({
type: "PATCH", type: "PATCH",
url: $(this).data('change-state-url'), url: $(this).data('change-state-url'),
...@@ -142,7 +142,11 @@ $(document).ready(function(){ ...@@ -142,7 +142,11 @@ $(document).ready(function(){
location.reload(); location.reload();
}, },
error: function (response) { error: function (response) {
$('#stateChangeError').html(response.responseJSON.name); if (response.responseJSON) {
$('#stateChangeError').html(response.responseJSON.name);
} else {
$('#stateChangeError').html(gettext('Something went wrong! please try again later.'));
}
$('#stateChangeAlert').show(); $('#stateChangeAlert').show();
console.log(response); console.log(response);
} }
......
...@@ -51,3 +51,12 @@ ...@@ -51,3 +51,12 @@
border-color: #169BD5; border-color: #169BD5;
border-radius: 5px; border-radius: 5px;
} }
.btn-publish {
@include padding(5px, 30px, 5px, 30px);
@include float(right);
background-color: #169BD5;
border-color: #169BD5;
border-radius: 5px;
margin-top: 10px;
}
...@@ -621,3 +621,10 @@ ...@@ -621,3 +621,10 @@
color: red; color: red;
} }
} }
.published-status {
@include text-align(center);
padding-top: 20px;
padding-bottom: 20px;
font-size: 14px;
}
{% load i18n %} {% load i18n %}
<div class="approval-widget"> <div class="approval-widget">
<div class="margin-top20"> <h5 class="hd-5 emphasized approvals-heading">{% trans "APPROVALS" %}</h5>
<h5 class="hd-5 emphasized approvals-heading">{% trans "APPROVALS" %}</h5>
</div>
{% if is_course_run and not object.course.course_state.is_approved %} {% if is_course_run and not object.course.course_state.is_approved %}
<div class="parent-course-approval"> <div class="parent-course-approval">
{% url 'publisher:publisher_course_detail' object.course.id as course_url %} {% url 'publisher:publisher_course_detail' object.course.id as course_url %}
......
...@@ -11,6 +11,16 @@ ...@@ -11,6 +11,16 @@
{% block page_content %} {% block page_content %}
<div class="layout-1t2t layout-flush publisher-container course-detail"> <div class="layout-1t2t layout-flush publisher-container course-detail">
<main class="layout-col layout-col-b layout-col-b-custom"> <main class="layout-col layout-col-b layout-col-b-custom">
{% if object.course_run_state.is_published %}
<div class="depth depth-0 published-status">
<strong>
{% blocktrans with publish_date|date:'m/d/y' as course_publish_date trimmed %}
Course run announced on {{ course_publish_date }} - view it on edx.org at:
{% endblocktrans %}
</strong>
<a href="{{ object.preview_url }}" target="_blank">{{ object.preview_url }}</a>
</div>
{% endif %}
<nav class="administration-nav"> <nav class="administration-nav">
<div class="tab-container"> <div class="tab-container">
{% if can_view_all_tabs %} {% if can_view_all_tabs %}
...@@ -35,6 +45,14 @@ ...@@ -35,6 +45,14 @@
{% include 'alert_messages.html' %} {% include 'alert_messages.html' %}
<div id="stateChangeAlert" class="alert-messages hidden">
<div class="alert alert-error" role="alert" tabindex="-1">
<div>
<p id="stateChangeError" class="alert-copy"></p>
</div>
</div>
</div>
<div class="tabs"> <div class="tabs">
<div id="tab-1" class="tab-content active"> <div id="tab-1" class="tab-content active">
{% include 'publisher/course_run_detail/_all.html' %} {% include 'publisher/course_run_detail/_all.html' %}
......
...@@ -28,6 +28,11 @@ ...@@ -28,6 +28,11 @@
{% trans "Approved" %}<br> {% trans "Approved" %}<br>
{{ preview_accepted_date|date:'m/d/y H:i a' }} {{ preview_accepted_date|date:'m/d/y H:i a' }}
</span> </span>
{% if object.course_run_state.is_ready_to_publish and object.course.publisher == request.user %}
<button class="btn-brand btn-base btn-publish" data-change-state-url="{% url 'publisher:api:change_course_run_state' object.course_run_state.id %}" data-state-name="{{ publish_state_name }}" type="button">
{% trans "Publish" %}
</button>
{% endif %}
{% elif object.course.publisher == request.user %} {% elif object.course.publisher == request.user %}
<span class="preview-status">{% trans "Submitted for review" %}</span> <span class="preview-status">{% trans "Submitted for review" %}</span>
<button data-url="{% url 'publisher:api:update_course_run' object.id %}" class="btn btn-neutral btn-edit-preview-url">{% trans "Edit" %}</button> <button data-url="{% url 'publisher:api:update_course_run' object.id %}" class="btn btn-neutral btn-edit-preview-url">{% trans "Edit" %}</button>
......
{% extends "publisher/email/email_base.html" %}
{% load i18n %}
{% block body %}
<!-- Message Body -->
<p>
{% blocktrans trimmed %}
Dear {{ recipient_name }},
{% endblocktrans %}
<p>
{% blocktrans with link_start='<a href="' link_middle='">' link_end='</a>' trimmed %}
Your course {{ link_start }}{{ page_url }}{{ link_middle }} {{ course_name }} {{ link_end }} is now live.
{% endblocktrans %}
</p>
{% comment %}Translators: It's closing of mail.{% endcomment %}
{% trans "Thanks," %}<br>
{% trans "The edX team" %}
{% blocktrans trimmed %}
<p>Note: This email address is unable to receive replies. For questions or comments, contact {{ contact_us_email }}.</p>
{% endblocktrans %}
<!-- End Message Body -->
{% endblock body %}
{% load i18n %}
{% blocktrans trimmed %}
Dear {{ recipient_name }},
{% endblocktrans %}
{% blocktrans trimmed %}
Your course {{ course_name }} is now live. {{ page_url }}
{% endblocktrans %}
{% trans "Thanks," %}
{% trans "The edX team" %}
{% blocktrans trimmed %}
Note: This email address is unable to receive replies. For questions or comments, contact {{ contact_us_email }}.
{% endblocktrans %}
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