129 lines
4.5 KiB
Python
129 lines
4.5 KiB
Python
from django.db.models.signals import m2m_changed, post_delete, post_save, pre_save
|
|
from django.dispatch import receiver
|
|
|
|
from apps.blog.models import Comment, Like, Post, SavedPost
|
|
from apps.events.models import Registration
|
|
from apps.gamification.services import (
|
|
desired_effect,
|
|
has_source_history,
|
|
invalidate_post_engagement,
|
|
sync_comment,
|
|
sync_effect,
|
|
sync_like,
|
|
sync_post_engagement_for_credited_authors,
|
|
sync_post_publication,
|
|
sync_registration_attendance,
|
|
sync_save,
|
|
sync_source_effects,
|
|
)
|
|
from apps.users.models import User
|
|
|
|
|
|
def _post_is_public(post):
|
|
return Post.StatusChoices.PUBLISHED == post.status and not post.is_deleted
|
|
|
|
|
|
def _credited_author_ids(post):
|
|
return {post.author_id, *post.writers.values_list("id", flat=True)}
|
|
|
|
|
|
@receiver(pre_save, sender=Post)
|
|
def remember_post_visibility(sender, instance, **kwargs):
|
|
if not instance.pk:
|
|
instance._gamification_was_public = False
|
|
return
|
|
old = Post.all_objects.filter(pk=instance.pk).values("status", "is_deleted").first()
|
|
instance._gamification_was_public = bool(
|
|
old
|
|
and old["status"] == Post.StatusChoices.PUBLISHED
|
|
and not old["is_deleted"]
|
|
)
|
|
|
|
|
|
@receiver(post_save, sender=Post)
|
|
def score_post_visibility(sender, instance, created, **kwargs):
|
|
was_public = getattr(instance, "_gamification_was_public", False)
|
|
is_public = _post_is_public(instance)
|
|
if is_public and not was_public:
|
|
sync_post_publication(instance, valid=True)
|
|
sync_post_engagement_for_credited_authors(instance)
|
|
elif was_public and not is_public:
|
|
sync_post_publication(instance, valid=False)
|
|
invalidate_post_engagement(instance)
|
|
|
|
|
|
@receiver(post_delete, sender=Post)
|
|
def reverse_deleted_post(sender, instance, **kwargs):
|
|
sync_source_effects("blog_post", instance.pk, [], reason="post was deleted")
|
|
|
|
|
|
@receiver(m2m_changed, sender=Post.writers.through)
|
|
def score_credited_writer_changes(sender, instance, action, reverse, pk_set, **kwargs):
|
|
if reverse or not _post_is_public(instance):
|
|
return
|
|
writer_ids = set(pk_set or getattr(instance, "_gamification_writer_ids_before_clear", set()))
|
|
if action in {"pre_clear"}:
|
|
instance._gamification_writer_ids_before_clear = set(instance.writers.values_list("id", flat=True))
|
|
return
|
|
if action not in {"post_add", "post_remove", "post_clear"}:
|
|
return
|
|
|
|
for user in User.objects.filter(pk__in=writer_ids):
|
|
if action != "post_add" and user.pk == instance.author_id:
|
|
continue
|
|
effect = {
|
|
**desired_effect(user, "post", "author"),
|
|
"source_type": "blog_post",
|
|
"source_id": str(instance.pk),
|
|
}
|
|
sync_effect(effect, valid=action == "post_add", reason="post coauthor credit was removed")
|
|
sync_post_engagement_for_credited_authors(instance)
|
|
instance._gamification_writer_ids_before_clear = set()
|
|
|
|
|
|
@receiver(pre_save, sender=Comment)
|
|
def remember_comment_approval(sender, instance, **kwargs):
|
|
if not instance.pk:
|
|
instance._gamification_was_approved = False
|
|
return
|
|
old = Comment.all_objects.filter(pk=instance.pk).values("is_approved", "is_hidden", "is_deleted").first()
|
|
instance._gamification_was_approved = bool(
|
|
old and old["is_approved"] and not old["is_hidden"] and not old["is_deleted"]
|
|
)
|
|
|
|
|
|
@receiver(post_save, sender=Comment)
|
|
def score_approved_comment(sender, instance, created, **kwargs):
|
|
became_approved = not getattr(instance, "_gamification_was_approved", False) and instance.is_approved
|
|
sync_comment(instance, allow_new=created or became_approved)
|
|
|
|
|
|
@receiver(post_delete, sender=Comment)
|
|
def reverse_deleted_comment(sender, instance, **kwargs):
|
|
sync_source_effects("blog_comment", instance.pk, [], reason="comment was deleted")
|
|
|
|
|
|
@receiver(post_save, sender=Like)
|
|
def score_like(sender, instance, created, **kwargs):
|
|
sync_like(instance, allow_new=created)
|
|
|
|
|
|
@receiver(post_delete, sender=Like)
|
|
def reverse_like(sender, instance, **kwargs):
|
|
sync_source_effects("blog_like", instance.pk, [], reason="like was removed")
|
|
|
|
|
|
@receiver(post_save, sender=SavedPost)
|
|
def score_saved_post(sender, instance, created, **kwargs):
|
|
sync_save(instance, allow_new=created)
|
|
|
|
|
|
@receiver(post_delete, sender=SavedPost)
|
|
def reverse_saved_post(sender, instance, **kwargs):
|
|
sync_source_effects("blog_save", instance.pk, [], reason="saved post was removed")
|
|
|
|
|
|
@receiver(post_save, sender=Registration)
|
|
def score_registration_attendance(sender, instance, **kwargs):
|
|
sync_registration_attendance(instance)
|