Commit 2f956826 by Waheed Ahmed

Course run mark as reviewed.

ECOM-6248
parent 0098e790
......@@ -155,13 +155,14 @@ class CourseStateSerializerTests(TestCase):
self.user = UserFactory()
self.request.user = self.user
CourseUserRoleFactory(
course=self.course_state.course, role=PublisherUserRole.CourseTeam, user=self.user
)
def test_update(self):
"""
Verify that we can update course workflow state with serializer.
"""
CourseUserRoleFactory(
course=self.course_state.course, role=PublisherUserRole.CourseTeam, user=self.user
)
course = self.course_state.course
course.image = make_image_file('test_banner.jpg')
course.save()
......
......@@ -481,6 +481,9 @@ class ChangeCourseStateViewTests(TestCase):
"""
Verify that user cannot change course workflow state directly from `Draft` to `Approved`.
"""
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.CourseTeam, user=self.user
)
response = self.client.patch(
self.change_state_url,
data=json.dumps({'name': CourseStateChoices.Approved}),
......@@ -576,11 +579,12 @@ class ChangeCourseRunStateViewTests(TestCase):
self.assertEqual(response.data, expected)
def test_mark_as_reviewed(self):
def test_send_for_review(self):
"""
Verify that user can mark course-run as reviewed.
Verify that user can change course-run workflow state and owner role will be changed to `CourseTeam`.
"""
self.run_state.name = CourseRunStateChoices.Draft
self.run_state.owner_role = PublisherUserRole.MarketingReviewer
self.run_state.save()
self._assign_role(self.course_run.course, PublisherUserRole.MarketingReviewer, self.user)
......@@ -599,6 +603,7 @@ class ChangeCourseRunStateViewTests(TestCase):
course_run_state = CourseRunState.objects.get(course_run=self.course_run)
self.assertEqual(course_run_state.name, CourseRunStateChoices.Review)
self.assertEqual(course_run_state.owner_role, PublisherUserRole.CourseTeam)
self.assertEqual(len(mail.outbox), 1)
......@@ -607,3 +612,31 @@ class ChangeCourseRunStateViewTests(TestCase):
factories.CourseUserRoleFactory(
course=course, role=role, user=user
)
def test_mark_as_reviewed(self):
"""
Verify that user can change course-run workflow state and owner role will be changed to `Publisher`.
"""
self.run_state.name = CourseRunStateChoices.Review
self.run_state.owner_role = PublisherUserRole.CourseTeam
self.run_state.save()
self._assign_role(self.course_run.course, PublisherUserRole.CourseTeam, self.user)
self._assign_role(self.course_run.course, PublisherUserRole.MarketingReviewer, UserFactory())
self._assign_role(self.course_run.course, PublisherUserRole.Publisher, UserFactory())
response = self.client.patch(
self.change_state_url,
data=json.dumps({'name': CourseStateChoices.Approved}),
content_type=JSON_CONTENT_TYPE
)
self.assertEqual(response.status_code, 200)
self.run_state = CourseRunState.objects.get(course_run=self.course_run)
self.assertEqual(self.run_state.name, CourseRunStateChoices.Approved)
self.assertEqual(self.run_state.owner_role, PublisherUserRole.Publisher)
self.assertEqual(len(mail.outbox), 2)
......@@ -185,7 +185,7 @@ def send_email_for_mark_as_reviewed(course, user):
logger.exception('Failed to send email notifications mark as reviewed of course %s', course.id)
def send_course_workflow_email(course, user, subject, txt_template, html_template, page_path):
def send_course_workflow_email(course, user, subject, txt_template, html_template, page_path, course_name=None):
""" Send email for course workflow state change.
Arguments:
......@@ -194,6 +194,8 @@ def send_course_workflow_email(course, user, subject, txt_template, html_templat
subject (String): Email subject
txt_template: (String): Email text template path
html_template: (String): Email html template path
page_path: (URL): Detail page url
course_name: (String): Custom course name, by default None
"""
recipient_user = course.marketing_reviewer
user_role = course.course_user_roles.get(user=user)
......@@ -207,7 +209,7 @@ def send_course_workflow_email(course, user, subject, txt_template, html_templat
context = {
'recipient_name': recipient_user.full_name or recipient_user.username if recipient_user else '',
'sender_name': user.full_name or user.username,
'course_name': course.title,
'course_name': course_name if course_name else course.title,
'contact_us_email': partner_coordinator.email if partner_coordinator else '',
'page_url': 'https://{host}{path}'.format(
host=Site.objects.get_current().domain.strip('/'), path=page_path
......@@ -241,3 +243,80 @@ def send_email_for_send_for_review_course_run(course_run, user):
send_course_workflow_email(course_run.course, user, subject, txt_template, html_template, page_path)
except Exception: # pylint: disable=broad-except
logger.exception('Failed to send email notifications send for review of course-run %s', course_run.id)
def send_email_for_mark_as_reviewed_course_run(course_run, user):
""" Send email when course-run is marked as reviewed.
Arguments:
course-run (Object): CourseRun object
user (Object): User object
"""
txt_template = 'publisher/email/course_run/mark_as_reviewed.txt'
html_template = 'publisher/email/course_run/mark_as_reviewed.html'
run_name = '{pacing_type}: {start_date}'.format(
pacing_type=course_run.get_pacing_type_display(),
start_date=course_run.start.strftime("%B %d, %Y")
)
subject = _('Changes to {run_name} has been marked as reviewed').format(run_name=run_name) # pylint: disable=no-member
try:
page_path = reverse('publisher:publisher_course_run_detail', kwargs={'pk': course_run.id})
send_course_workflow_email(
course_run.course,
user,
subject,
txt_template,
html_template,
page_path,
course_name=run_name
)
except Exception: # pylint: disable=broad-except
logger.exception('Failed to send email notifications for mark as reviewed of course-run %s', course_run.id)
def send_email_to_publisher(course_run, user):
""" Send email to publisher when course-run is marked as reviewed.
Arguments:
course_run (Object): CourseRun object
user (Object): User object
"""
txt_template = 'publisher/email/course_run/mark_as_reviewed.txt'
html_template = 'publisher/email/course_run/mark_as_reviewed.html'
run_name = '{pacing_type}: {start_date}'.format(
pacing_type=course_run.get_pacing_type_display(),
start_date=course_run.start.strftime("%B %d, %Y")
)
subject = _('Changes to {run_name} has been marked as reviewed').format(run_name=run_name) # pylint: disable=no-member
recipient_user = course_run.course.publisher
try:
if is_email_notification_enabled(recipient_user):
partner_coordinator = course_run.course.partner_coordinator
to_addresses = [recipient_user.email]
from_address = settings.PUBLISHER_FROM_EMAIL
page_path = reverse('publisher:publisher_course_run_detail', kwargs={'pk': course_run.id})
context = {
'recipient_name': recipient_user.full_name or recipient_user.username if recipient_user else '',
'sender_name': user.full_name or user.username,
'course_name': run_name,
'contact_us_email': partner_coordinator.email if partner_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_addresses
)
email_msg.attach_alternative(html_content, 'text/html')
email_msg.send()
except Exception: # pylint: disable=broad-except
logger.exception('Failed to send email notifications for mark as reviewed of course-run %s', course_run.id)
......@@ -22,11 +22,8 @@ from course_discovery.apps.course_metadata.choices import CourseRunPacing
from course_discovery.apps.course_metadata.models import LevelType, Organization, Person, Subject
from course_discovery.apps.course_metadata.utils import UploadToFieldNamePath
from course_discovery.apps.ietf_language_tags.models import LanguageTag
from course_discovery.apps.publisher import emails
from course_discovery.apps.publisher.choices import CourseRunStateChoices, CourseStateChoices, PublisherUserRole
from course_discovery.apps.publisher.emails import (
send_email_for_change_state, send_email_for_mark_as_reviewed,
send_email_for_send_for_review, send_email_for_send_for_review_course_run
)
from course_discovery.apps.publisher.utils import is_email_notification_enabled
logger = logging.getLogger(__name__)
......@@ -161,9 +158,9 @@ class Course(TimeStampedModel, ChangedByMixin):
"""
users_list_roles = [obj.user for obj in self.course_user_roles.all()]
emails = [user.email for user in users_list_roles if is_email_notification_enabled(user)]
user_emails = [user.email for user in users_list_roles if is_email_notification_enabled(user)]
return emails
return user_emails
@property
def keywords_data(self):
......@@ -218,6 +215,13 @@ class Course(TimeStampedModel, ChangedByMixin):
return None
@property
def publisher(self):
try:
return self.course_user_roles.get(role=PublisherUserRole.Publisher).user
except CourseUserRole.DoesNotExist:
return None
class CourseRun(TimeStampedModel, ChangedByMixin):
""" Publisher CourseRun model. It contains fields related to the course run intake form."""
......@@ -318,7 +322,7 @@ class CourseRun(TimeStampedModel, ChangedByMixin):
self.state.save()
if waffle.switch_is_active('enable_publisher_email_notifications'):
send_email_for_change_state(self)
emails.send_email_for_change_state(self)
@property
def current_state(self):
......@@ -603,13 +607,16 @@ class CourseState(TimeStampedModel, ChangedByMixin):
self.review()
if waffle.switch_is_active('enable_publisher_email_notifications'):
send_email_for_send_for_review(self.course, user)
emails.send_email_for_send_for_review(self.course, user)
elif state == CourseStateChoices.Approved:
user_role = self.course.course_user_roles.get(user=user)
self.approved_by_role = user_role.role
self.owner_role_modified = timezone.now()
self.approved()
if waffle.switch_is_active('enable_publisher_email_notifications'):
send_email_for_mark_as_reviewed(self.course, user)
emails.send_email_for_mark_as_reviewed(self.course, user)
self.save()
......@@ -683,10 +690,19 @@ class CourseRunState(TimeStampedModel, ChangedByMixin):
self.review()
if waffle.switch_is_active('enable_publisher_email_notifications'):
send_email_for_send_for_review_course_run(self.course_run, user)
emails.send_email_for_send_for_review_course_run(self.course_run, user)
elif state == CourseRunStateChoices.Approved:
user_role = self.course_run.course.course_user_roles.get(user=user)
self.approved_by_role = user_role.role
self.owner_role = PublisherUserRole.Publisher
self.owner_role_modified = timezone.now()
self.approved()
if waffle.switch_is_active('enable_publisher_email_notifications'):
emails.send_email_for_mark_as_reviewed_course_run(self.course_run, user)
emails.send_email_to_publisher(self.course_run, user)
elif state == CourseRunStateChoices.Published:
self.published()
......
......@@ -62,13 +62,13 @@ class StateChangeEmailTests(TestCase):
toggle_switch('enable_publisher_email_notifications', True)
@mock.patch('course_discovery.apps.publisher.models.send_email_for_change_state')
@mock.patch('course_discovery.apps.publisher.emails.send_email_for_change_state')
def test_email_with_enable_waffle_switch(self, send_email_for_change_state):
""" Verify that send_email_for_state called with enable waffle switch.. """
self.course_run.change_state(target=State.DRAFT)
send_email_for_change_state.assert_called_once_with(self.course_run)
@mock.patch('course_discovery.apps.publisher.models.send_email_for_change_state')
@mock.patch('course_discovery.apps.publisher.emails.send_email_for_change_state')
def test_email_with_waffle_switch_disabled(self, send_email_for_change_state):
""" Verify that send_email_for_state not called with disable waffle switch.. """
toggle_switch('enable_publisher_email_notifications', False)
......@@ -309,11 +309,11 @@ class CourseMarkAsReviewedEmailTests(TestCase):
)
class CourseRunMarkAsReviewedEmailTests(TestCase):
""" Tests for the email functionality for mark as reviewed. """
class CourseRunSendForReviewEmailTests(TestCase):
""" Tests for the email functionality for send for review. """
def setUp(self):
super(CourseRunMarkAsReviewedEmailTests, self).setUp()
super(CourseRunSendForReviewEmailTests, self).setUp()
self.user = UserFactory()
self.user_2 = UserFactory()
self.user_3 = UserFactory()
......@@ -376,3 +376,98 @@ class CourseRunMarkAsReviewedEmailTests(TestCase):
page_url = 'https://{host}{path}'.format(host=Site.objects.get_current().domain.strip('/'), path=page_path)
self.assertIn(page_url, body)
self.assertIn('are ready for your review.', body)
class CourseRunMarkAsReviewedEmailTests(TestCase):
""" Tests email functionality of mark as reviewed. """
def setUp(self):
super(CourseRunMarkAsReviewedEmailTests, self).setUp()
self.user = UserFactory()
self.user_2 = UserFactory()
self.user_3 = UserFactory()
self.seat = factories.SeatFactory()
self.course_run = self.seat.course_run
self.course = self.course_run.course
# add user in course-user-role table
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.CourseTeam, user=self.user_2
)
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.Publisher, user=self.user_3
)
self.course_run_state = factories.CourseRunStateFactory(course_run=self.course_run)
toggle_switch('enable_publisher_email_notifications', True)
def test_email_sent_by_marketing_reviewer(self):
""" Verify that email works successfully."""
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.MarketingReviewer, user=self.user
)
emails.send_email_for_mark_as_reviewed_course_run(self.course_run_state.course_run, self.user)
self.assert_email_sent(self.user_2)
def test_email_sent_by_course_team(self):
""" Verify that email works successfully."""
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.MarketingReviewer, user=self.user
)
emails.send_email_for_mark_as_reviewed_course_run(self.course_run_state.course_run, self.user_2)
self.assert_email_sent(self.user)
def test_email_mark_as_reviewed_with_error(self):
""" Verify that email failure log error message."""
with LogCapture(emails.logger.name) as l:
emails.send_email_for_mark_as_reviewed_course_run(self.course_run, self.user)
l.check(
(
emails.logger.name,
'ERROR',
'Failed to send email notifications for mark as reviewed of course-run {}'.format(
self.course_run.id
)
)
)
def test_email_sent_to_publisher(self):
""" Verify that email works successfully."""
emails.send_email_to_publisher(self.course_run_state.course_run, self.user)
self.assert_email_sent(self.user_3)
def test_email_to_publisher_with_error(self):
""" Verify that email failure log error message."""
with mock.patch('django.core.mail.message.EmailMessage.send', side_effect=TypeError):
with LogCapture(emails.logger.name) as l:
emails.send_email_to_publisher(self.course_run, self.user_3)
l.check(
(
emails.logger.name,
'ERROR',
'Failed to send email notifications for mark as reviewed of course-run {}'.format(
self.course_run.id
)
)
)
def assert_email_sent(self, to_email):
""" Verify the email data for tests cases."""
run_name = '{pacing_type}: {start_date}'.format(
pacing_type=self.course_run.get_pacing_type_display(),
start_date=self.course_run.start.strftime("%B %d, %Y")
)
subject = 'Changes to {run_name} has been marked as reviewed'.format(
run_name=run_name
)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(to_email.email, mail.outbox[0].to[0])
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('has been marked as reviewed.', body)
......@@ -314,6 +314,16 @@ class CourseTests(TestCase):
self.assertEqual(self.user1, self.course2.marketing_reviewer)
def test_publisher(self):
""" Verify that the publisher property returns user if exist. """
self.assertIsNone(self.course2.publisher)
factories.CourseUserRoleFactory(
course=self.course2, user=self.user1, role=PublisherUserRole.Publisher
)
self.assertEqual(self.user1, self.course2.publisher)
class SeatTests(TestCase):
""" Tests for the publisher `Seat` model. """
......
......@@ -1031,9 +1031,6 @@ class CourseRunDetailTests(TestCase):
factories.CourseUserRoleFactory(
course=self.course, user=self.user, role=PublisherUserRole.CourseTeam
)
self.course_state.owner_role = PublisherUserRole.MarketingReviewer
self.course_state.name = CourseStateChoices.Approved
self.course_state.save()
new_user = UserFactory()
factories.CourseUserRoleFactory(
......@@ -1063,8 +1060,6 @@ class CourseRunDetailTests(TestCase):
factories.CourseUserRoleFactory(
course=self.course, user=self.user, role=PublisherUserRole.MarketingReviewer
)
self.course_state.owner_role = PublisherUserRole.MarketingReviewer
self.course_state.save()
new_user = UserFactory()
factories.CourseUserRoleFactory(
......@@ -1119,6 +1114,58 @@ class CourseRunDetailTests(TestCase):
response = self.client.get(self.page_url)
self.assertContains(response, '<div class="parent-course-approval">')
def test_course_run_mark_as_reviewed(self):
"""
Verify that user can see mark as reviewed button on course detail page.
"""
toggle_switch('publisher_approval_widget_feature', True)
self.course_run_state.name = CourseRunStateChoices.Review
self.course_run_state.save()
factories.CourseUserRoleFactory(
course=self.course, user=self.user, role=PublisherUserRole.CourseTeam
)
factories.CourseUserRoleFactory(
course=self.course, user=UserFactory(), role=PublisherUserRole.MarketingReviewer
)
response = self.client.get(self.page_url)
# Verify that content is sent for review and user can see `Mark as Reviewed` button.
self.assertContains(response, 'Send for Review')
self.assertContains(response, '<span class="icon fa fa-check" aria-hidden="true">', count=1)
self.assertContains(response, 'Mark as Reviewed')
self.assertContains(response, self.get_expected_data(CourseRunStateChoices.Approved))
def test_course_with_reviewed(self):
"""
Verify that user can see approval widget on course detail page with `Reviewed`.
"""
factories.CourseUserRoleFactory(
course=self.course, user=self.user, role=PublisherUserRole.MarketingReviewer
)
factories.CourseUserRoleFactory(
course=self.course, user=UserFactory(), role=PublisherUserRole.CourseTeam
)
# To create history objects for both `Review` and `Approved` states
self.course_run_state.name = CourseStateChoices.Review
self.course_run_state.save()
self.course_run_state.name = CourseStateChoices.Approved
self.course_run_state.owner_role = PublisherUserRole.Publisher
self.course_run_state.approved_by_role = PublisherUserRole.CourseTeam
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)
# Verify that content is marked as reviewed and user can see Reviewed status.
self.assertNotContains(response, 'Mark as Reviewed')
self.assertContains(response, 'Reviewed', count=1)
self.assertContains(response, '<span class="icon fa fa-check" aria-hidden="true">', count=2)
self.assertContains(response, 'Send for Review', count=1)
# pylint: disable=attribute-defined-outside-init
@ddt.ddt
......@@ -1686,16 +1733,13 @@ class CourseDetailViewTests(TestCase):
course=self.course, user=self.user, role=PublisherUserRole.MarketingReviewer
)
self.course_state.owner_role = PublisherUserRole.MarketingReviewer
self.course_state.name = CourseStateChoices.Review
self.course_state.save()
new_user = UserFactory()
factories.CourseUserRoleFactory(
course=self.course, user=new_user, role=PublisherUserRole.CourseTeam
course=self.course, user=UserFactory(), role=PublisherUserRole.CourseTeam
)
self.course.course_state.name = CourseStateChoices.Review
self.course.course_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.detail_page_url)
......@@ -1723,25 +1767,24 @@ class CourseDetailViewTests(TestCase):
factories.CourseUserRoleFactory(
course=self.course, user=self.user, role=PublisherUserRole.MarketingReviewer
)
self.course_state.owner_role = PublisherUserRole.MarketingReviewer
self.course_state.save()
new_user = UserFactory()
factories.CourseUserRoleFactory(
course=self.course, user=new_user, role=PublisherUserRole.CourseTeam
course=self.course, user=UserFactory(), role=PublisherUserRole.CourseTeam
)
# To create history objects for both `Review` and `Approved` states
self.course.course_state.name = CourseStateChoices.Review
self.course.course_state.save()
self.course.course_state.name = CourseStateChoices.Approved
self.course.course_state.save()
self.course_state.name = CourseStateChoices.Review
self.course_state.save()
self.course_state.name = CourseStateChoices.Approved
self.course_state.owner_role = PublisherUserRole.Publisher
self.course_state.approved_by_role = PublisherUserRole.CourseTeam
self.course_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.detail_page_url)
# Verify that content is sent for review and user can see Reviewed button.
# Verify that content is marked as reviewed and user can see Reviewed status.
self.assertNotContains(response, 'Mark as Reviewed')
self.assertContains(response, 'Reviewed', count=1)
self.assertContains(response, '<span class="icon fa fa-check" aria-hidden="true">', count=2)
......
......@@ -749,18 +749,19 @@ def get_course_role_widgets_data(user, course, state_object, change_state_url):
role_widget['button_disabled'] = True
if course_role.role in [PublisherUserRole.CourseTeam, PublisherUserRole.MarketingReviewer]:
if state_object.owner_role != course_role.role:
if state_object.name != CourseStateChoices.Draft:
history_records = state_object.history.filter(
name=CourseStateChoices.Review
).order_by('-modified')
role_widget['sent_for_review'] = history_records.first() and history_records.first().modified
if state_object.name == CourseStateChoices.Approved:
history_records = state_object.history.filter(
if state_object.name == CourseStateChoices.Approved and course_role.role == state_object.approved_by_role:
history_record = state_object.history.filter(
name=CourseStateChoices.Approved
).order_by('-modified')
role_widget['reviewed'] = history_records.first().modified
).order_by('-modified').first()
if history_record:
role_widget['reviewed'] = history_record.modified
elif state_object.name != CourseStateChoices.Draft and course_role.role != state_object.owner_role:
history_record = state_object.history.filter(
name=CourseStateChoices.Review
).order_by('-modified').first()
if history_record:
role_widget['sent_for_review'] = history_record.modified
role_widgets.append(role_widget)
......
......@@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-02-20 17:52+0500\n"
"POT-Creation-Date: 2017-02-21 13:08+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
#: apps/api/filters.py
#, python-brace-format
......@@ -495,6 +495,11 @@ msgstr ""
msgid "Changes to {title} has been approved"
msgstr ""
#: apps/publisher/emails.py
#, python-brace-format
msgid "Changes to {run_name} has been marked as reviewed"
msgstr ""
#: apps/publisher/forms.py
msgid "Remove Image"
msgstr ""
......@@ -2308,6 +2313,8 @@ msgstr ""
#: templates/publisher/email/course/mark_as_reviewed.txt
#: templates/publisher/email/course/send_for_review.html
#: 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.txt
#: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/course_run/send_for_review.txt
#, python-format
......@@ -2328,6 +2335,8 @@ msgstr ""
#: templates/publisher/email/course/send_for_review.txt
#: templates/publisher/email/course_created.html
#: templates/publisher/email/course_created.txt
#: templates/publisher/email/course_run/mark_as_reviewed.html
#: templates/publisher/email/course_run/mark_as_reviewed.txt
#: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/course_run/send_for_review.txt
#: templates/publisher/email/studio_instance_created.html
......@@ -2339,6 +2348,7 @@ msgstr ""
#: templates/publisher/email/course/mark_as_reviewed.html
#: templates/publisher/email/course/send_for_review.html
#: templates/publisher/email/course_run/mark_as_reviewed.html
#: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/studio_instance_created.html
#, python-format
......@@ -2354,6 +2364,7 @@ msgstr ""
#: templates/publisher/email/course/mark_as_reviewed.txt
#: templates/publisher/email/course/send_for_review.txt
#: templates/publisher/email/course_run/mark_as_reviewed.txt
#: templates/publisher/email/course_run/send_for_review.txt
#: templates/publisher/email/studio_instance_created.txt
#, python-format
......@@ -2411,6 +2422,18 @@ msgid ""
" in Publisher on %(date)s at %(time)s."
msgstr ""
#: templates/publisher/email/course_run/mark_as_reviewed.html
#, python-format
msgid ""
"Changes to %(link_start)s%(page_url)s%(link_middle)s %(course_name)s "
"%(link_end)s has been marked as reviewed."
msgstr ""
#: templates/publisher/email/course_run/mark_as_reviewed.txt
#, python-format
msgid "Changes to %(course_name)s has been marked as reviewed. %(page_url)s"
msgstr ""
#: templates/publisher/email/course_run/send_for_review.html
#, python-format
msgid ""
......
......@@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-02-20 17:52+0500\n"
"POT-Creation-Date: 2017-02-21 13:08+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
#: static/js/catalogs-change-form.js
msgid "Preview"
......
......@@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-02-20 17:52+0500\n"
"POT-Creation-Date: 2017-02-21 13:08+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: apps/api/filters.py
......@@ -614,6 +614,13 @@ msgid "Changes to {title} has been approved"
msgstr ""
"Çhängés tö {title} häs ßéén äpprövéd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#"
#: apps/publisher/emails.py
#, python-brace-format
msgid "Changes to {run_name} has been marked as reviewed"
msgstr ""
"Çhängés tö {run_name} häs ßéén märkéd äs révïéwéd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт "
"αмєт, ¢σηѕє¢тєтυя #"
#: apps/publisher/forms.py
msgid "Remove Image"
msgstr "Rémövé Ìmägé Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#"
......@@ -2711,6 +2718,8 @@ msgstr "Vïéw çömmént: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#"
#: templates/publisher/email/course/mark_as_reviewed.txt
#: templates/publisher/email/course/send_for_review.html
#: 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.txt
#: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/course_run/send_for_review.txt
#, python-format
......@@ -2733,6 +2742,8 @@ msgstr ""
#: templates/publisher/email/course/send_for_review.txt
#: templates/publisher/email/course_created.html
#: templates/publisher/email/course_created.txt
#: templates/publisher/email/course_run/mark_as_reviewed.html
#: templates/publisher/email/course_run/mark_as_reviewed.txt
#: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/course_run/send_for_review.txt
#: templates/publisher/email/studio_instance_created.html
......@@ -2744,6 +2755,7 @@ msgstr "Thänks, Ⱡ'σяєм ιρѕυм #"
#: templates/publisher/email/course/mark_as_reviewed.html
#: templates/publisher/email/course/send_for_review.html
#: templates/publisher/email/course_run/mark_as_reviewed.html
#: templates/publisher/email/course_run/send_for_review.html
#: templates/publisher/email/studio_instance_created.html
#, python-format
......@@ -2763,6 +2775,7 @@ msgstr ""
#: templates/publisher/email/course/mark_as_reviewed.txt
#: templates/publisher/email/course/send_for_review.txt
#: templates/publisher/email/course_run/mark_as_reviewed.txt
#: templates/publisher/email/course_run/send_for_review.txt
#: templates/publisher/email/studio_instance_created.txt
#, python-format
......@@ -2844,6 +2857,23 @@ msgstr ""
" ïn Püßlïshér ön %(date)s ät %(time)s. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
"¢σηѕє¢тєтυя α#"
#: templates/publisher/email/course_run/mark_as_reviewed.html
#, python-format
msgid ""
"Changes to %(link_start)s%(page_url)s%(link_middle)s %(course_name)s "
"%(link_end)s has been marked as reviewed."
msgstr ""
"Çhängés tö %(link_start)s%(page_url)s%(link_middle)s %(course_name)s "
"%(link_end)s häs ßéén märkéd äs révïéwéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
"¢σηѕє¢тєтυя α#"
#: templates/publisher/email/course_run/mark_as_reviewed.txt
#, python-format
msgid "Changes to %(course_name)s has been marked as reviewed. %(page_url)s"
msgstr ""
"Çhängés tö %(course_name)s häs ßéén märkéd äs révïéwéd. %(page_url)s Ⱡ'σяєм "
"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
#: templates/publisher/email/course_run/send_for_review.html
#, python-format
msgid ""
......
......@@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-02-20 17:52+0500\n"
"POT-Creation-Date: 2017-02-21 13:08+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/js/catalogs-change-form.js
......
{% 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 %}
Changes to {{ link_start }}{{ page_url }}{{ link_middle }} {{ course_name }} {{ link_end }} has been marked as reviewed.
{% endblocktrans %}
</p>
{% comment %}Translators: It's closing of mail.{% endcomment %}
{% trans "Thanks," %}<br>
{{ sender_name }}
{% 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 %}
Changes to {{ course_name }} has been marked as reviewed. {{ page_url }}
{% endblocktrans %}
{% trans "Thanks," %}
{{ sender_name }}
{% 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