participants.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. User = 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. User.objects.filter(id__in=set(users_ids)).update(sync_unread_private_threads=True)
  49. def set_owner(thread, user):
  50. ThreadParticipant.objects.set_owner(thread, user)
  51. def change_owner(request, thread, new_owner):
  52. ThreadParticipant.objects.set_owner(thread, new_owner)
  53. set_users_unread_private_threads_sync(
  54. participants=thread.participants_list, exclude_user=request.user
  55. )
  56. if thread.participant and thread.participant.is_owner:
  57. record_event(
  58. request,
  59. thread,
  60. "changed_owner",
  61. {
  62. "user": {
  63. "id": new_owner.id,
  64. "username": new_owner.username,
  65. "url": new_owner.get_absolute_url(),
  66. }
  67. },
  68. )
  69. else:
  70. record_event(request, thread, "tookover")
  71. def add_participant(request, thread, new_participant):
  72. """adds single participant to thread, registers this on the event"""
  73. add_participants(request, thread, [new_participant])
  74. if request.user == new_participant:
  75. record_event(request, thread, "entered_thread")
  76. else:
  77. record_event(
  78. request,
  79. thread,
  80. "added_participant",
  81. {
  82. "user": {
  83. "id": new_participant.id,
  84. "username": new_participant.username,
  85. "url": new_participant.get_absolute_url(),
  86. }
  87. },
  88. )
  89. def add_participants(request, thread, users):
  90. """
  91. Add multiple participants to thread, set "recound private threads" flag on them
  92. notify them about being added to thread.
  93. """
  94. ThreadParticipant.objects.add_participants(thread, users)
  95. try:
  96. thread_participants = thread.participants_list
  97. except AttributeError:
  98. thread_participants = []
  99. set_users_unread_private_threads_sync(
  100. users=users, participants=thread_participants, exclude_user=request.user
  101. )
  102. emails = []
  103. for user in users:
  104. if user != request.user:
  105. emails.append(build_noticiation_email(request, thread, user))
  106. if emails:
  107. send_messages(emails)
  108. def build_noticiation_email(request, thread, user):
  109. subject = _(
  110. '%(user)s has invited you to participate in private thread "%(thread)s"'
  111. )
  112. subject_formats = {"thread": thread.title, "user": request.user.username}
  113. return build_mail(
  114. user,
  115. subject % subject_formats,
  116. "misago/emails/privatethread/added",
  117. sender=request.user,
  118. context={"settings": request.settings, "thread": thread},
  119. )
  120. def remove_participant(request, thread, user):
  121. """remove thread participant, set "recound private threads" flag on user"""
  122. removed_owner = False
  123. remaining_participants = []
  124. for participant in thread.participants_list:
  125. if participant.user == user:
  126. removed_owner = participant.is_owner
  127. else:
  128. remaining_participants.append(participant.user)
  129. set_users_unread_private_threads_sync(participants=thread.participants_list)
  130. if not remaining_participants:
  131. thread.delete()
  132. else:
  133. thread.threadparticipant_set.filter(user=user).delete()
  134. thread.subscription_set.filter(user=user).delete()
  135. if removed_owner:
  136. thread.is_closed = True # flag thread to close
  137. if request.user == user:
  138. event_type = "owner_left"
  139. else:
  140. event_type = "removed_owner"
  141. else:
  142. if request.user == user:
  143. event_type = "participant_left"
  144. else:
  145. event_type = "removed_participant"
  146. record_event(
  147. request,
  148. thread,
  149. event_type,
  150. {
  151. "user": {
  152. "id": user.id,
  153. "username": user.username,
  154. "url": user.get_absolute_url(),
  155. }
  156. },
  157. )