feat: updated content in course_update notification (#35373)

This commit is contained in:
Muhammad Adeel Tajamul
2024-08-29 06:07:57 -07:00
committed by GitHub
parent 1c2b804ef7
commit 481a50717a
3 changed files with 63 additions and 4 deletions

View File

@@ -9,6 +9,7 @@ import ddt
from django.conf import settings
from django.test import TestCase
from django.test.utils import override_settings
from edx_toggles.toggles.testutils import override_waffle_flag
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locator import CourseLocator, LibraryLocator
from path import Path as path
@@ -19,7 +20,11 @@ from user_tasks.models import UserTaskArtifact, UserTaskStatus
from cms.djangoapps.contentstore import utils
from cms.djangoapps.contentstore.tasks import ALL_ALLOWED_XBLOCKS, validate_course_olx
from cms.djangoapps.contentstore.tests.utils import TEST_DATA_DIR, CourseTestCase
from cms.djangoapps.contentstore.utils import send_course_update_notification
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.tests.factories import GlobalStaffFactory, InstructorFactory, UserFactory
from openedx.core.djangoapps.notifications.config.waffle import ENABLE_NOTIFICATIONS
from openedx.core.djangoapps.notifications.models import CourseNotificationPreference, Notification
from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration_context
from xmodule.modulestore import ModuleStoreEnum # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
@@ -927,3 +932,32 @@ class UpdateCourseDetailsTests(ModuleStoreTestCase):
utils.update_course_details(mock_request, self.course.id, payload, None)
mock_update.assert_called_once_with(self.course.id, payload, mock_request.user)
@override_waffle_flag(ENABLE_NOTIFICATIONS, active=True)
class CourseUpdateNotificationTests(ModuleStoreTestCase):
"""
Unit tests for the course_update notification.
"""
def setUp(self):
"""
Setup the test environment.
"""
super().setUp()
self.user = UserFactory()
self.course = CourseFactory.create(org='testorg', number='testcourse', run='testrun')
CourseNotificationPreference.objects.create(user_id=self.user.id, course_id=self.course.id)
def test_course_update_notification_sent(self):
"""
Test that the course_update notification is sent.
"""
user = UserFactory()
CourseEnrollment.enroll(user=user, course_key=self.course.id)
assert Notification.objects.all().count() == 0
content = "<p>content</p><img src='' />"
send_course_update_notification(self.course.id, content, self.user)
assert Notification.objects.all().count() == 1
notification = Notification.objects.first()
assert notification.content == "<p><strong><p>content</p></strong></p>"

View File

@@ -11,16 +11,19 @@ from datetime import datetime, timezone
from urllib.parse import quote_plus
from uuid import uuid4
from bs4 import BeautifulSoup
from django.conf import settings
from django.core.exceptions import ValidationError
from django.urls import reverse
from django.utils import translation
from django.utils.text import Truncator
from django.utils.translation import gettext as _
from eventtracking import tracker
from help_tokens.core import HelpUrlExpert
from lti_consumer.models import CourseAllowPIISharingInLTIFlag
from opaque_keys.edx.keys import CourseKey, UsageKey
from opaque_keys.edx.locator import LibraryLocator
from openedx.core.lib.teams_config import CONTENT_GROUPS_FOR_TEAMS, TEAM_SCHEME
from openedx_events.content_authoring.data import DuplicatedXBlockData
from openedx_events.content_authoring.signals import XBLOCK_DUPLICATED
@@ -2239,11 +2242,34 @@ def track_course_update_event(course_key, user, course_update_content=None):
tracker.emit(event_name, event_data)
def clean_html_body(html_body):
"""
Get html body, remove tags and limit to 500 characters
"""
html_body = BeautifulSoup(Truncator(html_body).chars(500, html=True), 'html.parser')
tags_to_remove = [
"a", "link", # Link Tags
"img", "picture", "source", # Image Tags
"video", "track", # Video Tags
"audio", # Audio Tags
"embed", "object", "iframe", # Embedded Content
"script"
]
# Remove the specified tags while keeping their content
for tag in tags_to_remove:
for match in html_body.find_all(tag):
match.unwrap()
return str(html_body)
def send_course_update_notification(course_key, content, user):
"""
Send course update notification
"""
text_content = re.sub(r"(\s|&nbsp;|//)+", " ", html_to_text(content))
text_content = re.sub(r"(\s|&nbsp;|//)+", " ", clean_html_body(content))
course = modulestore().get_course(course_key)
extra_context = {
'author_id': user.id,
@@ -2252,7 +2278,7 @@ def send_course_update_notification(course_key, content, user):
notification_data = CourseNotificationData(
course_key=course_key,
content_context={
"course_update_content": text_content if len(text_content.strip()) < 10 else "Click here to view",
"course_update_content": text_content,
**extra_context,
},
notification_type="course_updates",

View File

@@ -181,8 +181,7 @@ COURSE_NOTIFICATION_TYPES = {
'push': True,
'email_cadence': EmailCadence.DAILY,
'non_editable': [],
'content_template': _('<{p}>You have a new course update: '
'<{strong}>{course_update_content}</{strong}></{p}>'),
'content_template': _('<{p}><{strong}>{course_update_content}</{strong}></{p}>'),
'content_context': {
'course_update_content': 'Course update',
},