createfakeforumhistory.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import random
  2. import time
  3. from datetime import timedelta
  4. from django.contrib.auth import get_user_model
  5. from django.core.management.base import BaseCommand
  6. from django.utils import timezone
  7. from faker import Factory
  8. from ....categories.models import Category
  9. from ....threads.checksums import update_post_checksum
  10. from ....threads.models import Post, Thread
  11. from ....users.models import Rank
  12. from ...englishcorpus import EnglishCorpus
  13. from ...users import (
  14. get_fake_inactive_user,
  15. get_fake_admin_activated_user,
  16. get_fake_banned_user,
  17. get_fake_user,
  18. )
  19. User = get_user_model()
  20. corpus = EnglishCorpus()
  21. corpus_short = EnglishCorpus(max_length=150)
  22. USER = 0
  23. THREAD = 1
  24. POST = 2
  25. ACTIONS = [USER, THREAD, POST, POST, POST]
  26. class Command(BaseCommand):
  27. help = "Creates fake forum history reaching specified period."
  28. def add_arguments(self, parser):
  29. parser.add_argument(
  30. "length",
  31. help="generated history length (in days)",
  32. nargs="?",
  33. type=int,
  34. default=5,
  35. )
  36. def handle(self, *args, **options):
  37. history_length = options["length"]
  38. fake = Factory.create()
  39. categories = list(Category.objects.all_categories())
  40. ranks = list(Rank.objects.all())
  41. message = "Creating fake forum history for %s days...\n"
  42. self.stdout.write(message % history_length)
  43. start_time = time.time()
  44. self.move_existing_users_to_past(history_length)
  45. start_timestamp = timezone.now()
  46. for days_ago in reversed(range(history_length)):
  47. date = start_timestamp - timedelta(days=days_ago)
  48. for date_variation in get_random_date_variations(date, 0, 20):
  49. action = random.choice(ACTIONS)
  50. if action == USER:
  51. self.create_fake_user(fake, date_variation, ranks)
  52. elif action == THREAD:
  53. self.create_fake_thread(fake, date_variation, categories)
  54. elif action == POST:
  55. self.create_fake_post(fake, date_variation)
  56. total_time = time.time() - start_time
  57. total_humanized = time.strftime("%H:%M:%S", time.gmtime(total_time))
  58. message = "\n\nSuccessfully created fake history for %s days in %s"
  59. self.stdout.write(message % (history_length, total_humanized))
  60. def move_existing_users_to_past(self, history_length):
  61. for user in User.objects.all():
  62. user.joined_on -= timedelta(days=history_length)
  63. user.save(update_fields=["joined_on"])
  64. user.audittrail_set.all().delete()
  65. def create_fake_user(self, fake, date, ranks):
  66. # There's 40% chance user has registered on this day
  67. if random.randint(1, 100) > 25:
  68. return
  69. # Pick random rank for next user
  70. rank = random.choice(ranks)
  71. # There's 10% chance user is inactive
  72. if random.randint(0, 100) > 90:
  73. user = get_fake_inactive_user(fake, rank)
  74. # There's another 10% chance user is admin-activated
  75. elif random.randint(0, 100) > 90:
  76. user = get_fake_admin_activated_user(fake, rank)
  77. # And further chance user is banned
  78. elif random.randint(0, 100) > 90:
  79. user = get_fake_banned_user(fake, rank)
  80. # User is active
  81. else:
  82. user = get_fake_user(fake, rank)
  83. user.joined_on = date
  84. user.save(update_fields=["joined_on"])
  85. user.audittrail_set.all().delete()
  86. self.write_event(date, "%s has joined" % user)
  87. def create_fake_thread(self, fake, date, categories):
  88. user = self.get_random_user(date)
  89. category = random.choice(categories)
  90. thread_is_unapproved = random.randint(0, 100) > 90
  91. thread_is_hidden = random.randint(0, 100) > 90
  92. thread_is_closed = random.randint(0, 100) > 90
  93. thread = Thread(
  94. category=category,
  95. started_on=datetime,
  96. starter_name="-",
  97. starter_slug="-",
  98. last_post_on=datetime,
  99. last_poster_name="-",
  100. last_poster_slug="-",
  101. replies=0,
  102. is_unapproved=thread_is_unapproved,
  103. is_hidden=thread_is_hidden,
  104. is_closed=thread_is_closed,
  105. )
  106. thread.set_title(corpus_short.random_sentence())
  107. thread.save()
  108. self.write_event(date, '%s has started "%s" thread' % (user, "TODO"))
  109. def create_fake_post(self, fake, date):
  110. user = self.get_random_user(date)
  111. self.write_event(date, '%s has replied to "%s" thread' % (user, "TODO"))
  112. def get_random_user(self, date):
  113. return User.objects.filter(joined_on__lt=date).order_by("?").first()
  114. def write_event(self, date, event):
  115. formatted_date = date.strftime("%Y-%m-%d %H:%M")
  116. self.stdout.write("%s: %s" % (formatted_date, event))
  117. def get_random_date_variations(date, min, max):
  118. variations = []
  119. for _ in range(random.randint(min, max)):
  120. random_offset = timedelta(minutes=random.randint(1, 1200))
  121. variations.append(date - random_offset)
  122. return sorted(variations)