Files
edx-platform/lms/djangoapps/discussion/signals/handlers.py
Ivan Niedielnitsev 28eb406f8d feat: [FC-0047] add settings for edx-ace push notifications
feat: [FC-0047] Add push notifications for user enroll

feat: [FC-0047] Add push notifications for user unenroll

feat: [FC-0047] Add push notifications for add course beta testers

feat: [FC-0047] Add push notifications for remove course beta testers

feat: [FC-0047] Add push notification event to discussions
2024-09-05 15:29:48 +03:00

197 lines
7.5 KiB
Python

"""
Signal handlers related to discussions.
"""
import logging
from django.conf import settings
from django.dispatch import receiver
from django.utils.html import strip_tags
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locator import LibraryLocator
from lms.djangoapps.discussion import tasks
from lms.djangoapps.discussion.rest_api.discussions_notifications import DiscussionNotificationSender
from lms.djangoapps.discussion.rest_api.tasks import (
send_response_endorsed_notifications,
send_response_notifications,
send_thread_created_notification
)
from openedx.core.djangoapps.django_comment_common import signals
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
from openedx.core.djangoapps.theming.helpers import get_current_site
from xmodule.modulestore.django import SignalHandler, modulestore
log = logging.getLogger(__name__)
ENABLE_FORUM_NOTIFICATIONS_FOR_SITE_KEY = 'enable_forum_notifications'
@receiver(SignalHandler.course_published)
def update_discussions_on_course_publish(sender, course_key, **kwargs): # pylint: disable=unused-argument
"""
Catches the signal that a course has been published in the module
store and creates/updates the corresponding cache entry.
Ignores publish signals from content libraries.
"""
if isinstance(course_key, LibraryLocator):
return
context = {
'course_id': str(course_key),
}
tasks.update_discussions_map.apply_async(
args=[context],
countdown=settings.DISCUSSION_SETTINGS['COURSE_PUBLISH_TASK_DELAY'],
)
@receiver(signals.comment_created)
def send_discussion_email_notification(sender, user, post,
**kwargs): # lint-amnesty, pylint: disable=missing-function-docstring, unused-argument
current_site = get_current_site()
if current_site is None:
log.info('Discussion: No current site, not sending notification about post: %s.', post.id)
return
try:
if not current_site.configuration.get_value(ENABLE_FORUM_NOTIFICATIONS_FOR_SITE_KEY, False):
log_message = 'Discussion: notifications not enabled for site: %s. Not sending message about post: %s.'
log.info(log_message, current_site, post.id)
return
except SiteConfiguration.DoesNotExist:
log_message = 'Discussion: No SiteConfiguration for site %s. Not sending message about post: %s.'
log.info(log_message, current_site, post.id)
return
send_message(post, current_site)
@receiver(signals.comment_flagged)
@receiver(signals.thread_flagged)
def send_reported_content_email_notification(sender, user, post, **kwargs):
"""
Sends email notification for reported content.
"""
current_site = get_current_site()
if current_site is None:
log.info('Discussion: No current site, not sending notification about post: %s.', post.id)
return
try:
if not current_site.configuration.get_value(ENABLE_FORUM_NOTIFICATIONS_FOR_SITE_KEY, False):
log_message = 'Discussion: reported content notifications not enabled for site: %s. ' \
'Not sending message about post: %s.'
log.info(log_message, current_site, post.id)
return
except SiteConfiguration.DoesNotExist:
log_message = 'Discussion: No SiteConfiguration for site %s. Not sending message about post: %s.'
log.info(log_message, current_site, post.id)
return
send_message_for_reported_content(user, post, current_site, sender)
@receiver(signals.comment_flagged)
@receiver(signals.thread_flagged)
def send_reported_content_notification(sender, user, post, **kwargs):
"""
Sends notification for reported content.
"""
course_key = CourseKey.from_string(post.course_id)
course = modulestore().get_course(course_key)
DiscussionNotificationSender(post, course, user).send_reported_content_notification()
def create_message_context(comment, site):
thread = comment.thread
return {
'course_id': str(thread.course_id),
'comment_id': comment.id,
'comment_body': comment.body,
'comment_body_text': comment.body_text,
'comment_author_id': comment.user_id,
'comment_created_at': comment.created_at, # comment_client models dates are already serialized
'comment_parent_id': comment.parent_id,
'thread_id': thread.id,
'thread_title': thread.title,
'thread_author_id': thread.user_id,
'thread_created_at': thread.created_at, # comment_client models dates are already serialized
'thread_commentable_id': thread.commentable_id,
'site_id': site.id
}
def create_message_context_for_reported_content(user, post, site, sender):
"""
Create message context for reported content.
"""
def get_comment_type(comment):
"""
Returns type of comment.
"""
return 'response' if comment.get('parent_id', None) is None else 'comment'
context = {
'user_id': user.id,
'course_id': str(post.course_id),
'thread_id': post.thread.id if sender == 'flag_abuse_for_comment' else post.id,
'title': post.thread.title if sender == 'flag_abuse_for_comment' else post.title,
'content_type': 'post' if sender == 'flag_abuse_for_thread' else get_comment_type(post),
'content_body': strip_tags(post.body),
'thread_created_at': post.created_at,
'thread_commentable_id': post.commentable_id,
'site_id': site.id,
'comment_id': post.id if sender == 'flag_abuse_for_comment' else None,
}
return context
def send_message(comment, site): # lint-amnesty, pylint: disable=missing-function-docstring
context = create_message_context(comment, site)
tasks.send_ace_message.apply_async(args=[context])
def send_message_for_reported_content(user, post, site,
sender): # lint-amnesty, pylint: disable=missing-function-docstring
context = create_message_context_for_reported_content(user, post, site, sender)
tasks.send_ace_message_for_reported_content.apply_async(args=[context], countdown=120)
@receiver(signals.thread_created)
def create_thread_created_notification(*args, **kwargs):
"""
Creates a notification when new thread is created
"""
user = kwargs['user']
post = kwargs['post']
send_thread_created_notification.apply_async(args=[post.id, post.attributes['course_id'], user.id])
@receiver(signals.comment_created)
def create_comment_created_notification(*args, **kwargs):
"""
Creates a notification when new response or comment is created
"""
user = kwargs['user']
comment = kwargs['post']
thread_id = comment.attributes['thread_id']
parent_id = comment.attributes['parent_id']
comment_id = comment.attributes['id']
course_key_str = comment.attributes['course_id']
send_response_notifications.apply_async(args=[thread_id, course_key_str, user.id, comment_id, parent_id])
@receiver(signals.comment_endorsed)
def create_response_endorsed_on_thread_notification(*args, **kwargs):
"""
Creates a notification for thread author when response on thread is endorsed
and another notification for response author when response is endorsed
"""
comment = kwargs['post']
thread_id = comment.attributes['thread_id']
course_key_str = comment.attributes['course_id']
endorsed_by = kwargs['user'].id
send_response_endorsed_notifications.apply_async(args=[thread_id, kwargs['post'].id, course_key_str, endorsed_by])