Commit f8189381 by Tasawer Nawaz Committed by GitHub

Merge pull request #495 from edx/tasawer/ecom-6526-email-on-comment-update

Tasawer/ecom 6526 email on comment update
parents 3b678be0 e95ae92b
...@@ -160,8 +160,12 @@ class Course(TimeStampedModel, ChangedByMixin): ...@@ -160,8 +160,12 @@ class Course(TimeStampedModel, ChangedByMixin):
""" Returns the list of users emails with enable email notifications """ Returns the list of users emails with enable email notifications
against a course group. By default if attribute value does not exists against a course group. By default if attribute value does not exists
then user will be eligible for emails. then user will be eligible for emails.
Also get users from course-user-role table.
""" """
users_list = get_users_with_perms(self) users_list_perms = get_users_with_perms(self)
users_list_roles = [obj.user for obj in self.course_user_roles.all()]
users_list = set(list(users_list_perms) + list(users_list_roles))
emails = [user.email for user in users_list if is_email_notification_enabled(user)] emails = [user.email for user in users_list if is_email_notification_enabled(user)]
return emails return emails
......
...@@ -129,9 +129,19 @@ class CourseTests(TestCase): ...@@ -129,9 +129,19 @@ class CourseTests(TestCase):
self.course.assign_permission_by_group(self.org_extension_1.group) self.course.assign_permission_by_group(self.org_extension_1.group)
self.assertListEqual(self.course.get_group_users_emails(), [self.user1.email, self.user3.email]) self.assertListEqual(self.course.get_group_users_emails(), [self.user1.email, self.user3.email])
# add user in course-user-role table
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.PartnerCoordinator, user=self.user2
)
self.assertListEqual(
self.course.get_group_users_emails(),
[self.user1.email, self.user2.email, self.user3.email]
)
# The email addresses of users who have disabled email notifications should NOT be returned. # The email addresses of users who have disabled email notifications should NOT be returned.
factories.UserAttributeFactory(user=self.user1, enable_email_notification=False) factories.UserAttributeFactory(user=self.user1, enable_email_notification=False)
self.assertListEqual(self.course.get_group_users_emails(), [self.user3.email]) self.assertListEqual(self.course.get_group_users_emails(), [self.user2.email, self.user3.email])
def test_keywords_data(self): def test_keywords_data(self):
""" Verify that the property returns the keywords as comma separated string. """ """ Verify that the property returns the keywords as comma separated string. """
......
...@@ -12,21 +12,32 @@ from course_discovery.apps.publisher.models import CourseRun ...@@ -12,21 +12,32 @@ from course_discovery.apps.publisher.models import CourseRun
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def send_email_for_comment(comment): def send_email_for_comment(comment, created=False):
""" Send the emails for a comment. """ Send the emails for a comment.
Arguments: Arguments:
comment (Comment): Comment object comment (Comment): Comment object
created (Bool): Value indicating comment is created or updated
""" """
try: try:
object_pk = comment.object_pk object_pk = comment.object_pk
publisher_obj = comment.content_type.get_object_for_this_type(pk=object_pk) publisher_obj = comment.content_type.get_object_for_this_type(pk=object_pk)
comment_class = comment.content_type.model_class() comment_class = comment.content_type.model_class()
subject_desc = _('New comment added')
if not created:
subject_desc = _('Comment updated')
if comment_class == CourseRun: if comment_class == CourseRun:
course = publisher_obj.course course = publisher_obj.course
object_path = reverse('publisher:publisher_course_run_detail', args=[publisher_obj.id]) object_path = reverse('publisher:publisher_course_run_detail', args=[publisher_obj.id])
subject = _('New comment added in course run: {title}-{pacing_type}-{start}').format(
# Translators: subject_desc will be choice from ('New comment added', 'Comment updated'),
# 'pacing_type' will be choice from ('instructor-paced', 'self-paced'),
# 'title' and 'start' will be the value of course title & start date fields.
subject = _('{subject_desc} in course run: {title}-{pacing_type}-{start}').format(
subject_desc=subject_desc,
title=course.title, title=course.title,
pacing_type=publisher_obj.get_pacing_type_display(), pacing_type=publisher_obj.get_pacing_type_display(),
start=publisher_obj.start.strftime('%B %d, %Y') if publisher_obj.start else '' start=publisher_obj.start.strftime('%B %d, %Y') if publisher_obj.start else ''
...@@ -34,7 +45,13 @@ def send_email_for_comment(comment): ...@@ -34,7 +45,13 @@ def send_email_for_comment(comment):
else: else:
course = publisher_obj course = publisher_obj
object_path = reverse('publisher:publisher_courses_edit', args=[publisher_obj.id]) object_path = reverse('publisher:publisher_courses_edit', args=[publisher_obj.id])
subject = _('New comment added in Course: {title}').format(title=course.title)
# Translators: 'subject_desc' will be choice from ('New comment added', 'Comment updated')
# and 'title' will be the value of course title field.
subject = _('{subject_desc} in Course: {title}').format(
subject_desc=subject_desc,
title=course.title
)
to_addresses = course.get_group_users_emails() to_addresses = course.get_group_users_emails()
from_address = settings.PUBLISHER_FROM_EMAIL from_address = settings.PUBLISHER_FROM_EMAIL
......
...@@ -16,4 +16,4 @@ class Comments(CommentAbstractModel): ...@@ -16,4 +16,4 @@ class Comments(CommentAbstractModel):
def send_email(sender, instance, **kwargs): # pylint: disable=unused-argument def send_email(sender, instance, **kwargs): # pylint: disable=unused-argument
""" Send email on new comment. """ """ Send email on new comment. """
if waffle.switch_is_active('enable_publisher_email_notifications'): if waffle.switch_is_active('enable_publisher_email_notifications'):
send_email_for_comment(instance) send_email_for_comment(instance, kwargs.get('created', False))
...@@ -5,11 +5,11 @@ from django.contrib.sites.models import Site ...@@ -5,11 +5,11 @@ from django.contrib.sites.models import Site
from django.core import mail from django.core import mail
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test import TestCase from django.test import TestCase
from guardian.shortcuts import assign_perm
from course_discovery.apps.core.tests.factories import UserFactory from course_discovery.apps.core.tests.factories import UserFactory
from course_discovery.apps.course_metadata.tests import toggle_switch from course_discovery.apps.course_metadata.tests import toggle_switch
from course_discovery.apps.publisher.models import Course from course_discovery.apps.publisher.choices import PublisherUserRole
from course_discovery.apps.publisher.models import CourseUserRole
from course_discovery.apps.publisher.tests import factories from course_discovery.apps.publisher.tests import factories
from course_discovery.apps.publisher.tests.factories import UserAttributeFactory from course_discovery.apps.publisher.tests.factories import UserAttributeFactory
from course_discovery.apps.publisher_comments.tests.factories import CommentFactory from course_discovery.apps.publisher_comments.tests.factories import CommentFactory
...@@ -30,16 +30,23 @@ class CommentsEmailTests(TestCase): ...@@ -30,16 +30,23 @@ class CommentsEmailTests(TestCase):
self.organization_extension = factories.OrganizationExtensionFactory() self.organization_extension = factories.OrganizationExtensionFactory()
self.user.groups.add(self.organization_extension.group)
self.user_2.groups.add(self.organization_extension.group)
self.user_3.groups.add(self.organization_extension.group)
self.seat = factories.SeatFactory() self.seat = factories.SeatFactory()
self.course_run = self.seat.course_run self.course_run = self.seat.course_run
self.course = self.course_run.course self.course = self.course_run.course
# assign the role against a course
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.MarketingReviewer, user=self.user
)
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.PartnerCoordinator, user=self.user_2
)
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.Publisher, user=self.user_3
)
self.course.organizations.add(self.organization_extension.organization) self.course.organizations.add(self.organization_extension.organization)
assign_perm(Course.VIEW_PERMISSION, self.organization_extension.group, self.course)
# NOTE: We intentionally do NOT create an attribute for user_2. # NOTE: We intentionally do NOT create an attribute for user_2.
# By default this user WILL receive email notifications. # By default this user WILL receive email notifications.
...@@ -79,7 +86,7 @@ class CommentsEmailTests(TestCase): ...@@ -79,7 +86,7 @@ class CommentsEmailTests(TestCase):
def test_email_with_enable_waffle_switch(self, send_email_for_comment): def test_email_with_enable_waffle_switch(self, send_email_for_comment):
""" Verify that send_email_for_comment called with enable waffle switch.. """ """ Verify that send_email_for_comment called with enable waffle switch.. """
comment = self.create_comment(content_object=self.course) comment = self.create_comment(content_object=self.course)
send_email_for_comment.assert_called_once_with(comment) send_email_for_comment.assert_called_once_with(comment, True)
@mock.patch('course_discovery.apps.publisher_comments.models.send_email_for_comment') @mock.patch('course_discovery.apps.publisher_comments.models.send_email_for_comment')
def test_email_with_disable_waffle_switch(self, send_email_for_comment): def test_email_with_disable_waffle_switch(self, send_email_for_comment):
...@@ -88,11 +95,10 @@ class CommentsEmailTests(TestCase): ...@@ -88,11 +95,10 @@ class CommentsEmailTests(TestCase):
self.create_comment(content_object=self.course) self.create_comment(content_object=self.course)
send_email_for_comment.assert_not_called() send_email_for_comment.assert_not_called()
def test_email_without_different_group(self): def test_email_without_any_role(self):
""" Verify the emails behaviour if course group has no users. """ """ Verify the emails behaviour if course role has no users. """
self.user.groups.remove(self.organization_extension.group) CourseUserRole.objects.all().delete()
self.user_2.groups.remove(self.organization_extension.group)
self.user_3.groups.remove(self.organization_extension.group)
self.create_comment(content_object=self.course) self.create_comment(content_object=self.course)
self.assertEqual(len(mail.outbox), 0) self.assertEqual(len(mail.outbox), 0)
...@@ -131,6 +137,64 @@ class CommentsEmailTests(TestCase): ...@@ -131,6 +137,64 @@ class CommentsEmailTests(TestCase):
self.assertIn(page_url, body) self.assertIn(page_url, body)
self.assertIn('The edX team', body) self.assertIn('The edX team', body)
def test_email_with_roles(self):
""" Verify that emails send to the users against course-user-roles also."""
user_4 = UserFactory()
user_5 = UserFactory()
# assign the role against a course
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.MarketingReviewer, user=user_4
)
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.PartnerCoordinator, user=user_5
)
self.create_comment(content_object=self.course_run)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual([self.user.email, self.user_2.email, user_4.email, user_5.email], mail.outbox[0].to)
def test_email_for_roles_only(self):
""" Verify the emails send to the course roles users even if groups has no users. """
user_4 = UserFactory()
# assign the role against a course
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.MarketingReviewer, user=user_4
)
self.create_comment(content_object=self.course)
self.assertEqual(len(mail.outbox), 1)
def test_email_with_course_comment_editing(self):
""" Verify that after editing a comment against a course emails send
to multiple users.
"""
comment = self.create_comment(content_object=self.course)
subject = 'New comment added in Course: {title}'.format(title=self.course.title)
self.assertEqual(str(mail.outbox[0].subject), subject)
self.assertIn(comment.comment, str(mail.outbox[0].body.strip()))
comment.comment = 'update the comment'
comment.save() # pylint: disable=no-member
subject = 'Comment updated in Course: {title}'.format(title=self.course.title)
self.assertEqual(str(mail.outbox[1].subject), subject)
self.assertIn(comment.comment, str(mail.outbox[1].body.strip()), 'update the comment')
def test_email_with_course_run_comment_editing(self):
""" Verify that after editing a comment against a course emails send
to multiple users.
"""
comment = self.create_comment(content_object=self.course_run)
comment.comment = 'Update the comment'
comment.save() # pylint: disable=no-member
subject = 'Comment updated in course run: {title}-{pacing_type}-{start}'.format(
title=self.course_run.course.title,
pacing_type=self.course_run.get_pacing_type_display(),
start=self.course_run.start.strftime('%B %d, %Y')
)
self.assertEqual(str(mail.outbox[1].subject), subject)
self.assertIn(comment.comment, str(mail.outbox[1].body.strip()), 'Update the comment')
def create_comment(self, content_object): def create_comment(self, content_object):
""" DRY method to create the comment for a given content type.""" """ DRY method to create the comment for a given content type."""
return CommentFactory( return CommentFactory(
......
...@@ -7,6 +7,7 @@ from django.test import TestCase ...@@ -7,6 +7,7 @@ from django.test import TestCase
from course_discovery.apps.core.tests.factories import UserFactory, USER_PASSWORD from course_discovery.apps.core.tests.factories import UserFactory, USER_PASSWORD
from course_discovery.apps.course_metadata.tests import toggle_switch from course_discovery.apps.course_metadata.tests import toggle_switch
from course_discovery.apps.publisher.choices import PublisherUserRole
from course_discovery.apps.publisher.models import Seat from course_discovery.apps.publisher.models import Seat
from course_discovery.apps.publisher.tests import factories from course_discovery.apps.publisher.tests import factories
from course_discovery.apps.publisher_comments.tests.factories import CommentFactory from course_discovery.apps.publisher_comments.tests.factories import CommentFactory
...@@ -20,8 +21,6 @@ class CommentsTests(TestCase): ...@@ -20,8 +21,6 @@ class CommentsTests(TestCase):
self.user = UserFactory(is_staff=True, is_superuser=True) self.user = UserFactory(is_staff=True, is_superuser=True)
self.organization_extension = factories.OrganizationExtensionFactory() self.organization_extension = factories.OrganizationExtensionFactory()
self.user.groups.add(self.organization_extension.group)
self.client.login(username=self.user.username, password=USER_PASSWORD) self.client.login(username=self.user.username, password=USER_PASSWORD)
self.site = Site.objects.get(pk=settings.SITE_ID) self.site = Site.objects.get(pk=settings.SITE_ID)
self.course_edit_page = 'publisher:publisher_courses_edit' self.course_edit_page = 'publisher:publisher_courses_edit'
...@@ -34,7 +33,12 @@ class CommentsTests(TestCase): ...@@ -34,7 +33,12 @@ class CommentsTests(TestCase):
self.course = self.course_run.course self.course = self.course_run.course
self.course.organizations.add(self.organization_extension.organization) self.course.organizations.add(self.organization_extension.organization)
self.course.assign_permission_by_group(self.organization_extension.group)
# assign the role against a course
factories.CourseUserRoleFactory(
course=self.course, role=PublisherUserRole.MarketingReviewer, user=self.user
)
toggle_switch('enable_publisher_email_notifications', True) toggle_switch('enable_publisher_email_notifications', True)
def test_course_edit_page_with_multiple_comments(self): def test_course_edit_page_with_multiple_comments(self):
......
...@@ -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: 2016-12-19 14:36+0500\n" "POT-Creation-Date: 2016-12-21 15:19+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
...@@ -647,13 +647,28 @@ msgid "Publish" ...@@ -647,13 +647,28 @@ msgid "Publish"
msgstr "" msgstr ""
#: apps/publisher_comments/emails.py #: apps/publisher_comments/emails.py
msgid "New comment added"
msgstr ""
#: apps/publisher_comments/emails.py
msgid "Comment updated"
msgstr ""
#. Translators: subject_desc will be choice from ('New comment added',
#. 'Comment updated'),
#. 'pacing_type' will be choice from ('instructor-paced', 'self-paced'),
#. 'title' and 'start' will be the value of course title & start date fields.
#: apps/publisher_comments/emails.py
#, python-brace-format #, python-brace-format
msgid "New comment added in course run: {title}-{pacing_type}-{start}" msgid "{subject_desc} in course run: {title}-{pacing_type}-{start}"
msgstr "" msgstr ""
#. Translators: 'subject_desc' will be choice from ('New comment added',
#. 'Comment updated')
#. and 'title' will be the value of course title field.
#: apps/publisher_comments/emails.py #: apps/publisher_comments/emails.py
#, python-brace-format #, python-brace-format
msgid "New comment added in Course: {title}" msgid "{subject_desc} in Course: {title}"
msgstr "" msgstr ""
#: apps/publisher_comments/models.py #: apps/publisher_comments/models.py
......
...@@ -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: 2016-12-19 14:36+0500\n" "POT-Creation-Date: 2016-12-21 15:19+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"
......
...@@ -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: 2016-12-19 14:36+0500\n" "POT-Creation-Date: 2016-12-21 15:19+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
...@@ -778,17 +778,31 @@ msgid "Publish" ...@@ -778,17 +778,31 @@ msgid "Publish"
msgstr "Püßlïsh Ⱡ'σяєм ιρѕυм #" msgstr "Püßlïsh Ⱡ'σяєм ιρѕυм #"
#: apps/publisher_comments/emails.py #: apps/publisher_comments/emails.py
msgid "New comment added"
msgstr "Néw çömmént äddéd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#"
#: apps/publisher_comments/emails.py
msgid "Comment updated"
msgstr "Çömmént üpdätéd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#"
#. Translators: subject_desc will be choice from ('New comment added',
#. 'Comment updated'),
#. 'pacing_type' will be choice from ('instructor-paced', 'self-paced'),
#. 'title' and 'start' will be the value of course title & start date fields.
#: apps/publisher_comments/emails.py
#, python-brace-format #, python-brace-format
msgid "New comment added in course run: {title}-{pacing_type}-{start}" msgid "{subject_desc} in course run: {title}-{pacing_type}-{start}"
msgstr "" msgstr ""
"Néw çömmént äddéd ïn çöürsé rün: {title}-{pacing_type}-{start} Ⱡ'σяєм ιρѕυм " "{subject_desc} ïn çöürsé rün: {title}-{pacing_type}-{start} Ⱡ'σяєм ιρѕυм "
"∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" "∂σłσя ѕιт αмєт, ¢σηѕє¢т#"
#. Translators: 'subject_desc' will be choice from ('New comment added',
#. 'Comment updated')
#. and 'title' will be the value of course title field.
#: apps/publisher_comments/emails.py #: apps/publisher_comments/emails.py
#, python-brace-format #, python-brace-format
msgid "New comment added in Course: {title}" msgid "{subject_desc} in Course: {title}"
msgstr "" msgstr "{subject_desc} ïn Çöürsé: {title} Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#"
"Néw çömmént äddéd ïn Çöürsé: {title} Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#"
#: apps/publisher_comments/models.py #: apps/publisher_comments/models.py
msgid "modified" msgid "modified"
......
...@@ -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: 2016-12-19 14:36+0500\n" "POT-Creation-Date: 2016-12-21 15:19+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
......
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