|
@@ -0,0 +1,155 @@
|
|
|
+import random
|
|
|
+import time
|
|
|
+from datetime import timedelta
|
|
|
+
|
|
|
+from django.contrib.auth import get_user_model
|
|
|
+from django.core.management.base import BaseCommand
|
|
|
+from django.utils import timezone
|
|
|
+from faker import Factory
|
|
|
+
|
|
|
+from ....categories.models import Category
|
|
|
+from ....threads.checksums import update_post_checksum
|
|
|
+from ....threads.models import Post, Thread
|
|
|
+from ....users.models import Rank
|
|
|
+from ...englishcorpus import EnglishCorpus
|
|
|
+from ...users import (
|
|
|
+ get_fake_inactive_user,
|
|
|
+ get_fake_admin_activated_user,
|
|
|
+ get_fake_banned_user,
|
|
|
+ get_fake_user,
|
|
|
+)
|
|
|
+
|
|
|
+User = get_user_model()
|
|
|
+
|
|
|
+corpus = EnglishCorpus()
|
|
|
+corpus_short = EnglishCorpus(max_length=150)
|
|
|
+
|
|
|
+USER = 0
|
|
|
+THREAD = 1
|
|
|
+POST = 2
|
|
|
+ACTIONS = [USER, THREAD, POST, POST, POST]
|
|
|
+
|
|
|
+
|
|
|
+class Command(BaseCommand):
|
|
|
+ help = "Creates fake forum history reaching specified period."
|
|
|
+
|
|
|
+ def add_arguments(self, parser):
|
|
|
+ parser.add_argument(
|
|
|
+ "length",
|
|
|
+ help="generated history length (in days)",
|
|
|
+ nargs="?",
|
|
|
+ type=int,
|
|
|
+ default=5,
|
|
|
+ )
|
|
|
+
|
|
|
+ def handle(self, *args, **options):
|
|
|
+ history_length = options["length"]
|
|
|
+ fake = Factory.create()
|
|
|
+
|
|
|
+ categories = list(Category.objects.all_categories())
|
|
|
+ ranks = list(Rank.objects.all())
|
|
|
+
|
|
|
+ message = "Creating fake forum history for %s days...\n"
|
|
|
+ self.stdout.write(message % history_length)
|
|
|
+
|
|
|
+ start_time = time.time()
|
|
|
+
|
|
|
+ self.move_existing_users_to_past(history_length)
|
|
|
+
|
|
|
+ start_timestamp = timezone.now()
|
|
|
+ for days_ago in reversed(range(history_length)):
|
|
|
+ date = start_timestamp - timedelta(days=days_ago)
|
|
|
+ for date_variation in get_random_date_variations(date, 0, 20):
|
|
|
+ action = random.choice(ACTIONS)
|
|
|
+ if action == USER:
|
|
|
+ self.create_fake_user(fake, date_variation, ranks)
|
|
|
+ elif action == THREAD:
|
|
|
+ self.create_fake_thread(fake, date_variation, categories)
|
|
|
+ elif action == POST:
|
|
|
+ self.create_fake_post(fake, date_variation)
|
|
|
+
|
|
|
+ total_time = time.time() - start_time
|
|
|
+ total_humanized = time.strftime("%H:%M:%S", time.gmtime(total_time))
|
|
|
+ message = "\n\nSuccessfully created fake history for %s days in %s"
|
|
|
+ self.stdout.write(message % (history_length, total_humanized))
|
|
|
+
|
|
|
+ def move_existing_users_to_past(self, history_length):
|
|
|
+ for user in User.objects.all():
|
|
|
+ user.joined_on -= timedelta(days=history_length)
|
|
|
+ user.save(update_fields=["joined_on"])
|
|
|
+ user.audittrail_set.all().delete()
|
|
|
+
|
|
|
+ def create_fake_user(self, fake, date, ranks):
|
|
|
+ # There's 40% chance user has registered on this day
|
|
|
+ if random.randint(1, 100) > 25:
|
|
|
+ return
|
|
|
+
|
|
|
+ # Pick random rank for next user
|
|
|
+ rank = random.choice(ranks)
|
|
|
+
|
|
|
+ # There's 10% chance user is inactive
|
|
|
+ if random.randint(0, 100) > 90:
|
|
|
+ user = get_fake_inactive_user(fake, rank)
|
|
|
+
|
|
|
+ # There's another 10% chance user is admin-activated
|
|
|
+ elif random.randint(0, 100) > 90:
|
|
|
+ user = get_fake_admin_activated_user(fake, rank)
|
|
|
+
|
|
|
+ # And further chance user is banned
|
|
|
+ elif random.randint(0, 100) > 90:
|
|
|
+ user = get_fake_banned_user(fake, rank)
|
|
|
+
|
|
|
+ # User is active
|
|
|
+ else:
|
|
|
+ user = get_fake_user(fake, rank)
|
|
|
+
|
|
|
+ user.joined_on = date
|
|
|
+ user.save(update_fields=["joined_on"])
|
|
|
+ user.audittrail_set.all().delete()
|
|
|
+
|
|
|
+ self.write_event(date, "%s has joined" % user)
|
|
|
+
|
|
|
+ def create_fake_thread(self, fake, date, categories):
|
|
|
+ user = self.get_random_user(date)
|
|
|
+ category = random.choice(categories)
|
|
|
+
|
|
|
+ thread_is_unapproved = random.randint(0, 100) > 90
|
|
|
+ thread_is_hidden = random.randint(0, 100) > 90
|
|
|
+ thread_is_closed = random.randint(0, 100) > 90
|
|
|
+
|
|
|
+ thread = Thread(
|
|
|
+ category=category,
|
|
|
+ started_on=datetime,
|
|
|
+ starter_name="-",
|
|
|
+ starter_slug="-",
|
|
|
+ last_post_on=datetime,
|
|
|
+ last_poster_name="-",
|
|
|
+ last_poster_slug="-",
|
|
|
+ replies=0,
|
|
|
+ is_unapproved=thread_is_unapproved,
|
|
|
+ is_hidden=thread_is_hidden,
|
|
|
+ is_closed=thread_is_closed,
|
|
|
+ )
|
|
|
+ thread.set_title(corpus_short.random_sentence())
|
|
|
+ thread.save()
|
|
|
+
|
|
|
+ self.write_event(date, '%s has started "%s" thread' % (user, "TODO"))
|
|
|
+
|
|
|
+ def create_fake_post(self, fake, date):
|
|
|
+ user = self.get_random_user(date)
|
|
|
+ self.write_event(date, '%s has replied to "%s" thread' % (user, "TODO"))
|
|
|
+
|
|
|
+ def get_random_user(self, date):
|
|
|
+ return User.objects.filter(joined_on__lt=date).order_by("?").first()
|
|
|
+
|
|
|
+ def write_event(self, date, event):
|
|
|
+ formatted_date = date.strftime("%Y-%m-%d %H:%M")
|
|
|
+ self.stdout.write("%s: %s" % (formatted_date, event))
|
|
|
+
|
|
|
+
|
|
|
+def get_random_date_variations(date, min, max):
|
|
|
+ variations = []
|
|
|
+ for _ in range(random.randint(min, max)):
|
|
|
+ random_offset = timedelta(minutes=random.randint(1, 1200))
|
|
|
+ variations.append(date - random_offset)
|
|
|
+ return sorted(variations)
|