signals.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. from django.contrib.auth import get_user_model
  2. from django.db import transaction
  3. from django.db.models.signals import pre_delete
  4. from django.dispatch import Signal, receiver
  5. from django.urls import reverse
  6. from misago.categories.models import Category
  7. from misago.categories.signals import delete_category_content, move_category_content
  8. from misago.core.pgutils import batch_delete, batch_update
  9. from misago.core.utils import ANONYMOUS_IP
  10. from misago.users.signals import anonymize_user_content, delete_user_content, username_changed
  11. from .models import Attachment, Poll, PollVote, Post, PostEdit, PostLike, Thread
  12. delete_post = Signal()
  13. delete_thread = Signal()
  14. merge_post = Signal(providing_args=["other_post"])
  15. merge_thread = Signal(providing_args=["other_thread"])
  16. move_post = Signal()
  17. move_thread = Signal()
  18. @receiver(merge_thread)
  19. def merge_threads(sender, **kwargs):
  20. other_thread = kwargs['other_thread']
  21. other_thread.post_set.update(
  22. category=sender.category,
  23. thread=sender,
  24. )
  25. other_thread.postedit_set.update(
  26. category=sender.category,
  27. thread=sender,
  28. )
  29. other_thread.postlike_set.update(
  30. category=sender.category,
  31. thread=sender,
  32. )
  33. other_thread.subscription_set.exclude(
  34. user__in=sender.subscription_set.values('user'),
  35. ).update(
  36. category=sender.category,
  37. thread=sender,
  38. )
  39. @receiver(merge_post)
  40. def merge_posts(sender, **kwargs):
  41. other_post = kwargs['other_post']
  42. for user in sender.mentions.iterator():
  43. other_post.mentions.add(user)
  44. @receiver(move_thread)
  45. def move_thread_content(sender, **kwargs):
  46. sender.post_set.update(category=sender.category)
  47. sender.postedit_set.update(category=sender.category)
  48. sender.postlike_set.update(category=sender.category)
  49. sender.pollvote_set.update(category=sender.category)
  50. sender.subscription_set.update(category=sender.category)
  51. Poll.objects.filter(thread=sender).update(category=sender.category)
  52. @receiver(delete_category_content)
  53. def delete_category_threads(sender, **kwargs):
  54. sender.subscription_set.all().delete()
  55. sender.pollvote_set.all().delete()
  56. sender.poll_set.all().delete()
  57. sender.postlike_set.all().delete()
  58. sender.thread_set.all().delete()
  59. sender.postedit_set.all().delete()
  60. sender.post_set.all().delete()
  61. @receiver(move_category_content)
  62. def move_category_threads(sender, **kwargs):
  63. new_category = kwargs['new_category']
  64. sender.thread_set.update(category=new_category)
  65. sender.post_set.filter(category=sender).update(category=new_category)
  66. sender.postedit_set.filter(category=sender).update(category=new_category)
  67. sender.postlike_set.filter(category=sender).update(category=new_category)
  68. sender.poll_set.filter(category=sender).update(category=new_category)
  69. sender.pollvote_set.update(category=new_category)
  70. sender.subscription_set.update(category=new_category)
  71. @receiver(delete_user_content)
  72. def delete_user_threads(sender, **kwargs):
  73. recount_categories = set()
  74. recount_threads = set()
  75. for thread in batch_delete(sender.thread_set.all(), 50):
  76. recount_categories.add(thread.category_id)
  77. with transaction.atomic():
  78. thread.delete()
  79. for post in batch_delete(sender.post_set.all(), 50):
  80. recount_categories.add(post.category_id)
  81. recount_threads.add(post.thread_id)
  82. with transaction.atomic():
  83. post.delete()
  84. if recount_threads:
  85. changed_threads_qs = Thread.objects.filter(id__in=recount_threads)
  86. for thread in batch_update(changed_threads_qs, 50):
  87. thread.synchronize()
  88. thread.save()
  89. if recount_categories:
  90. for category in Category.objects.filter(id__in=recount_categories):
  91. category.synchronize()
  92. category.save()
  93. @receiver([delete_user_content])
  94. def delete_user_in_likes(sender, **kwargs):
  95. for post in sender.liked_post_set.iterator():
  96. cleaned_likes = list(filter(lambda i: i['id'] != sender.id, post.last_likes))
  97. if cleaned_likes != post.last_likes:
  98. post.last_likes = cleaned_likes
  99. post.save(update_fields=['last_likes'])
  100. @receiver(anonymize_user_content)
  101. def anonymize_user(sender, **kwargs):
  102. Post.objects.filter(poster=sender).update(poster_ip=ANONYMOUS_IP)
  103. PostEdit.objects.filter(editor=sender).update(editor_ip=ANONYMOUS_IP)
  104. PostLike.objects.filter(liker=sender).update(liker_ip=ANONYMOUS_IP)
  105. Attachment.objects.filter(uploader=sender).update(uploader_ip=ANONYMOUS_IP)
  106. Poll.objects.filter(poster=sender).update(poster_ip=ANONYMOUS_IP)
  107. PollVote.objects.filter(voter=sender).update(voter_ip=ANONYMOUS_IP)
  108. @receiver(anonymize_user_content)
  109. def anonymize_user_in_events(sender, **kwargs):
  110. queryset = Post.objects.filter(
  111. is_event=True,
  112. event_type__in=[
  113. 'added_participant',
  114. 'changed_owner',
  115. 'owner_left',
  116. 'removed_owner',
  117. 'participant_left',
  118. 'removed_participant',
  119. ],
  120. event_context__user__id=sender.id,
  121. ).iterator()
  122. for event in queryset:
  123. event.event_context = {
  124. 'user': {
  125. 'id': None,
  126. 'username': sender.username,
  127. 'url': reverse('misago:users'),
  128. },
  129. }
  130. event.save(update_fields=['event_context'])
  131. @receiver([anonymize_user_content])
  132. def anonymize_user_in_likes(sender, **kwargs):
  133. for post in sender.liked_post_set.iterator():
  134. cleaned_likes = []
  135. for like in post.last_likes:
  136. if like['id'] == sender.id:
  137. cleaned_likes.append({
  138. 'id': None,
  139. 'username': sender.username
  140. })
  141. else:
  142. cleaned_likes.append(like)
  143. if cleaned_likes != post.last_likes:
  144. post.last_likes = cleaned_likes
  145. post.save(update_fields=['last_likes'])
  146. @receiver([anonymize_user_content, username_changed])
  147. def update_usernames(sender, **kwargs):
  148. Thread.objects.filter(starter=sender).update(
  149. starter_name=sender.username,
  150. starter_slug=sender.slug,
  151. )
  152. Thread.objects.filter(last_poster=sender).update(
  153. last_poster_name=sender.username,
  154. last_poster_slug=sender.slug,
  155. )
  156. Thread.objects.filter(best_answer_marked_by=sender).update(
  157. best_answer_marked_by_name=sender.username,
  158. best_answer_marked_by_slug=sender.slug,
  159. )
  160. Post.objects.filter(poster=sender).update(
  161. poster_name=sender.username,
  162. )
  163. Post.objects.filter(last_editor=sender).update(
  164. last_editor_name=sender.username,
  165. last_editor_slug=sender.slug,
  166. )
  167. PostEdit.objects.filter(editor=sender).update(
  168. editor_name=sender.username,
  169. editor_slug=sender.slug,
  170. )
  171. PostLike.objects.filter(liker=sender).update(
  172. liker_name=sender.username,
  173. liker_slug=sender.slug,
  174. )
  175. Attachment.objects.filter(uploader=sender).update(
  176. uploader_name=sender.username,
  177. uploader_slug=sender.slug,
  178. )
  179. Poll.objects.filter(poster=sender).update(
  180. poster_name=sender.username,
  181. poster_slug=sender.slug,
  182. )
  183. PollVote.objects.filter(voter=sender).update(
  184. voter_name=sender.username,
  185. voter_slug=sender.slug,
  186. )
  187. @receiver(pre_delete, sender=get_user_model())
  188. def remove_unparticipated_private_threads(sender, **kwargs):
  189. threads_qs = kwargs['instance'].privatethread_set.all()
  190. for thread in batch_update(threads_qs, 50):
  191. if thread.participants.count() == 1:
  192. with transaction.atomic():
  193. thread.delete()