threadstracker.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. from django.db import transaction
  2. from django.utils import timezone
  3. from . import categoriestracker, signals
  4. from .dates import is_date_tracked
  5. from .models import CategoryRead, ThreadRead
  6. def make_read_aware(user, target):
  7. if not target:
  8. return
  9. if hasattr(target, '__iter__'):
  10. make_threads_read_aware(user, target)
  11. else:
  12. make_thread_read_aware(user, target)
  13. def make_threads_read_aware(user, threads):
  14. if not threads:
  15. return
  16. if user.is_anonymous:
  17. make_read(threads)
  18. else:
  19. make_categories_threads_read_aware(user, threads)
  20. def make_read(threads):
  21. for thread in threads:
  22. thread.is_read = True
  23. thread.is_new = False
  24. def make_unread(threads):
  25. for thread in threads:
  26. thread.is_read = False
  27. thread.is_new = True
  28. def make_categories_threads_read_aware(user, threads):
  29. categories_cutoffs = fetch_categories_cutoffs_for_threads(user, threads)
  30. threads_dict = {}
  31. for thread in threads:
  32. category_cutoff = categories_cutoffs.get(thread.category_id)
  33. thread.is_read = not is_date_tracked(thread.last_post_on, user, category_cutoff)
  34. thread.is_new = not thread.is_read
  35. thread.last_read_on = user.joined_on
  36. if not thread.is_read:
  37. threads_dict[thread.pk] = thread
  38. if threads_dict:
  39. make_threads_dict_read_aware(user, threads_dict)
  40. def fetch_categories_cutoffs_for_threads(user, threads):
  41. from misago.core import deprecations
  42. deprecations.warn("threadstracker.fetch_categories_cutoffs_for_threads has been deprecated")
  43. categories = []
  44. for thread in threads:
  45. if thread.category_id not in categories:
  46. categories.append(thread.category_id)
  47. categories_dict = {}
  48. for record in user.categoryread_set.filter(category__in=categories):
  49. categories_dict[record.category_id] = record.last_read_on
  50. return categories_dict
  51. def make_threads_dict_read_aware(user, threads_dict):
  52. for record in user.threadread_set.filter(thread__in=threads_dict.keys()):
  53. if record.thread_id in threads_dict:
  54. thread = threads_dict[record.thread_id]
  55. thread.is_read = record.last_read_on >= thread.last_post_on
  56. thread.is_new = not thread.is_read
  57. thread.last_read_on = record.last_read_on
  58. def make_thread_read_aware(user, thread):
  59. thread.is_read = True
  60. thread.is_new = False
  61. thread.read_record = None
  62. if user.is_anonymous:
  63. thread.last_read_on = timezone.now()
  64. else:
  65. thread.last_read_on = user.joined_on
  66. if user.is_authenticated and is_date_tracked(thread.last_post_on, user):
  67. thread.is_read = False
  68. thread.is_new = True
  69. try:
  70. category_record = user.categoryread_set.get(category_id=thread.category_id)
  71. thread.last_read_on = category_record.last_read_on
  72. if thread.last_post_on > category_record.last_read_on:
  73. try:
  74. thread_record = user.threadread_set.get(thread=thread)
  75. thread.last_read_on = thread_record.last_read_on
  76. if thread.last_post_on <= thread_record.last_read_on:
  77. thread.is_new = False
  78. thread.is_read = True
  79. thread.read_record = thread_record
  80. except ThreadRead.DoesNotExist:
  81. pass
  82. else:
  83. thread.is_read = True
  84. thread.is_new = False
  85. except CategoryRead.DoesNotExist:
  86. categoriestracker.start_record(user, thread.category)
  87. def make_posts_read_aware(user, thread, posts):
  88. from misago.core import deprecations
  89. deprecations.warn("threadstracker.make_posts_read_aware has been deprecated")
  90. try:
  91. is_thread_read = thread.is_read
  92. except AttributeError:
  93. raise ValueError(
  94. "thread passed make_posts_read_aware should be "
  95. "made read aware via make_thread_read_aware"
  96. )
  97. if is_thread_read:
  98. for post in posts:
  99. post.is_read = True
  100. post.is_new = False
  101. else:
  102. for post in posts:
  103. if is_date_tracked(post.posted_on, user):
  104. post.is_read = post.posted_on <= thread.last_read_on
  105. else:
  106. post.is_read = True
  107. post.is_new = not post.is_read
  108. def read_thread(user, thread, last_read_reply):
  109. from misago.core import deprecations
  110. deprecations.warn("threadstracker.read_thread has been deprecated")
  111. if not thread.is_read:
  112. if thread.last_read_on < last_read_reply.posted_on:
  113. sync_record(user, thread, last_read_reply)
  114. @transaction.atomic
  115. def sync_record(user, thread, last_read_reply):
  116. from misago.core import deprecations
  117. deprecations.warn("threadstracker.sync_record has been deprecated")
  118. notification_triggers = ['read_thread_%s' % thread.pk]
  119. if thread.read_record:
  120. thread.read_record.last_read_on = last_read_reply.posted_on
  121. thread.read_record.save(update_fields=['last_read_on'])
  122. else:
  123. user.threadread_set.create(
  124. category=thread.category,
  125. thread=thread,
  126. last_read_on=last_read_reply.posted_on,
  127. )
  128. signals.thread_tracked.send(sender=user, thread=thread)
  129. notification_triggers.append('see_thread_%s' % thread.pk)
  130. if last_read_reply.posted_on == thread.last_post_on:
  131. signals.thread_read.send(sender=user, thread=thread)
  132. categoriestracker.sync_record(user, thread.category)