participants.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. from django.contrib.auth import get_user_model
  2. from django.utils.translation import gettext as _
  3. from misago.core.mail import build_mail, send_messages
  4. from .events import record_event
  5. from .models import ThreadParticipant
  6. UserModel = get_user_model()
  7. def has_participants(thread):
  8. return thread.threadparticipant_set.exists()
  9. def make_participants_aware(user, target):
  10. if hasattr(target, "__iter__"):
  11. make_threads_participants_aware(user, target)
  12. else:
  13. make_thread_participants_aware(user, target)
  14. def make_threads_participants_aware(user, threads):
  15. threads_dict = {}
  16. for thread in threads:
  17. thread.participant = None
  18. threads_dict[thread.pk] = thread
  19. participants_qs = ThreadParticipant.objects.filter(
  20. user=user, thread_id__in=threads_dict.keys()
  21. )
  22. for participant in participants_qs:
  23. participant.user = user
  24. threads_dict[participant.thread_id].participant = participant
  25. def make_thread_participants_aware(user, thread):
  26. thread.participants_list = []
  27. thread.participant = None
  28. participants_qs = ThreadParticipant.objects.filter(thread=thread)
  29. participants_qs = participants_qs.select_related("user")
  30. for participant in participants_qs.order_by("-is_owner", "user__slug"):
  31. participant.thread = thread
  32. thread.participants_list.append(participant)
  33. if participant.user == user:
  34. thread.participant = participant
  35. return thread.participants_list
  36. def set_users_unread_private_threads_sync(
  37. users=None, participants=None, exclude_user=None
  38. ):
  39. users_ids = []
  40. if users:
  41. users_ids += [u.pk for u in users]
  42. if participants:
  43. users_ids += [p.user_id for p in participants]
  44. if exclude_user:
  45. users_ids = filter(lambda u: u != exclude_user.pk, users_ids)
  46. if not users_ids:
  47. return
  48. UserModel.objects.filter(id__in=set(users_ids)).update(
  49. sync_unread_private_threads=True
  50. )
  51. def set_owner(thread, user):
  52. ThreadParticipant.objects.set_owner(thread, user)
  53. def change_owner(request, thread, new_owner):
  54. ThreadParticipant.objects.set_owner(thread, new_owner)
  55. set_users_unread_private_threads_sync(
  56. participants=thread.participants_list, exclude_user=request.user
  57. )
  58. if thread.participant and thread.participant.is_owner:
  59. record_event(
  60. request,
  61. thread,
  62. "changed_owner",
  63. {
  64. "user": {
  65. "id": new_owner.id,
  66. "username": new_owner.username,
  67. "url": new_owner.get_absolute_url(),
  68. }
  69. },
  70. )
  71. else:
  72. record_event(request, thread, "tookover")
  73. def add_participant(request, thread, new_participant):
  74. """adds single participant to thread, registers this on the event"""
  75. add_participants(request, thread, [new_participant])
  76. if request.user == new_participant:
  77. record_event(request, thread, "entered_thread")
  78. else:
  79. record_event(
  80. request,
  81. thread,
  82. "added_participant",
  83. {
  84. "user": {
  85. "id": new_participant.id,
  86. "username": new_participant.username,
  87. "url": new_participant.get_absolute_url(),
  88. }
  89. },
  90. )
  91. def add_participants(request, thread, users):
  92. """
  93. Add multiple participants to thread, set "recound private threads" flag on them
  94. notify them about being added to thread.
  95. """
  96. ThreadParticipant.objects.add_participants(thread, users)
  97. try:
  98. thread_participants = thread.participants_list
  99. except AttributeError:
  100. thread_participants = []
  101. set_users_unread_private_threads_sync(
  102. users=users, participants=thread_participants, exclude_user=request.user
  103. )
  104. emails = []
  105. for user in users:
  106. if user != request.user:
  107. emails.append(build_noticiation_email(request, thread, user))
  108. if emails:
  109. send_messages(emails)
  110. def build_noticiation_email(request, thread, user):
  111. subject = _(
  112. '%(user)s has invited you to participate in private thread "%(thread)s"'
  113. )
  114. subject_formats = {"thread": thread.title, "user": request.user.username}
  115. return build_mail(
  116. user,
  117. subject % subject_formats,
  118. "misago/emails/privatethread/added",
  119. sender=request.user,
  120. context={"settings": request.settings, "thread": thread},
  121. )
  122. def remove_participant(request, thread, user):
  123. """remove thread participant, set "recound private threads" flag on user"""
  124. removed_owner = False
  125. remaining_participants = []
  126. for participant in thread.participants_list:
  127. if participant.user == user:
  128. removed_owner = participant.is_owner
  129. else:
  130. remaining_participants.append(participant.user)
  131. set_users_unread_private_threads_sync(participants=thread.participants_list)
  132. if not remaining_participants:
  133. thread.delete()
  134. else:
  135. thread.threadparticipant_set.filter(user=user).delete()
  136. thread.subscription_set.filter(user=user).delete()
  137. if removed_owner:
  138. thread.is_closed = True # flag thread to close
  139. if request.user == user:
  140. event_type = "owner_left"
  141. else:
  142. event_type = "removed_owner"
  143. else:
  144. if request.user == user:
  145. event_type = "participant_left"
  146. else:
  147. event_type = "removed_participant"
  148. record_event(
  149. request,
  150. thread,
  151. event_type,
  152. {
  153. "user": {
  154. "id": user.id,
  155. "username": user.username,
  156. "url": user.get_absolute_url(),
  157. }
  158. },
  159. )