counts.py 3.1 KB

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