counts.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. from time import time
  2. from django.conf import settings
  3. from django.db.models import F
  4. from django.dispatch import receiver
  5. from misago.categories.models import Category
  6. from misago.threads.views.moderatedcontent import ModeratedContent
  7. from misago.threads.views.newthreads import NewThreads
  8. from misago.threads.views.unreadthreads import UnreadThreads
  9. from misago.threads.views.privatethreads import PrivateThreads
  10. class BaseCounter(object):
  11. Threads = None
  12. name = None
  13. def __init__(self, user, session):
  14. self.user = user
  15. self.session = session
  16. self.count = self.get_cached_count()
  17. def __int__(self):
  18. return self.count
  19. def __unicode__(self):
  20. return unicode(self.count)
  21. def __nonzero__( self) :
  22. return bool(self.count)
  23. def get_cached_count(self):
  24. count = self.session.get(self.name, None)
  25. if not count or not self.is_cache_valid(count):
  26. count = self.get_current_count_dict()
  27. self.session[self.name] = count
  28. return count['threads']
  29. def is_cache_valid(self, cache):
  30. if cache.get('expires', 0) > time():
  31. return cache.get('user') == self.user.pk
  32. else:
  33. return False
  34. def get_expiration_timestamp(self):
  35. return time() + settings.MISAGO_CONTENT_COUNTING_FREQUENCY * 60
  36. def get_current_count_dict(self):
  37. return {
  38. 'user': self.user.pk,
  39. 'threads': self.count_threads(),
  40. 'expires': self.get_expiration_timestamp()
  41. }
  42. def count_threads(self):
  43. return self.Threads(self.user).get_queryset().count()
  44. def set(self, count):
  45. self.count = count
  46. self.session[self.name] = {
  47. 'user': self.user.pk,
  48. 'threads': count,
  49. 'expires': self.get_expiration_timestamp()
  50. }
  51. def decrease(self):
  52. if self.count > 0:
  53. self.count -= 1
  54. self.session[self.name] = {
  55. 'user': self.user.pk,
  56. 'threads': self.count,
  57. 'expires': self.session[self.name]['expires']
  58. }
  59. class ModeratedCount(BaseCounter):
  60. Threads = ModeratedContent
  61. name = 'moderated_content'
  62. class NewThreadsCount(BaseCounter):
  63. Threads = NewThreads
  64. name = 'new_threads'
  65. class UnreadThreadsCount(BaseCounter):
  66. Threads = UnreadThreads
  67. name = 'unread_threads'
  68. def sync_user_unread_private_threads_count(user):
  69. if not user.sync_unread_private_threads:
  70. return
  71. threads_qs = PrivateThreads(user).get_queryset()
  72. all_threads_count = threads_qs.count()
  73. read_qs = user.threadread_set.filter(
  74. category=Category.objects.private_threads())
  75. read_qs = read_qs.filter(last_read_on__gte=F('thread__last_post_on'))
  76. read_threads_count = read_qs.count()
  77. user.unread_private_threads = all_threads_count - read_threads_count
  78. if user.unread_private_threads < 0:
  79. # we may end with negative count because of race conditions in counts
  80. user.unread_private_threads = 0
  81. user.sync_unread_private_threads = False
  82. user.save(update_fields=[
  83. 'unread_private_threads', 'sync_unread_private_threads'
  84. ])