def setUp(self): # create dummy channel channel_id = uuid.uuid4().hex root = ContentNode.objects.create( id=uuid.uuid4().hex, title="root", channel_id=channel_id, content_id=uuid.uuid4().hex, ) min_timestamp = datetime.datetime(2018, 10, 11) self.channel = ChannelMetadata.objects.create( id=channel_id, name="channel", last_updated=min_timestamp, root=root) lf = LocalFile.objects.create( id=uuid.uuid4().hex, available=True, file_size=1048576 # 1 MB ) File.objects.create(id=uuid.uuid4().hex, contentnode=root, local_file=lf) # Load in the user data from the csv file to give a predictable source of user data data_path = os.path.join(USER_CSV_PATH) with io.open(data_path, mode="r", encoding="utf-8") as f: users = [data for data in csv.DictReader(f)] n_facilities = 1 n_classes = 1 # 1 class x 1 facility = 1 class n_users = 20 # 20 users x 1 facility = 20 users max_timestamp = datetime.datetime(2019, 10, 11) self.facilities = user_data.get_or_create_facilities( n_facilities=n_facilities) for facility in self.facilities: dataset = facility.dataset # create superuser and login session superuser = create_superuser(facility=facility) facility.add_role(superuser, role_kinds.ADMIN) UserSessionLog.objects.create( user=superuser, start_timestamp=min_timestamp, last_interaction_timestamp=max_timestamp, ) # create lesson and exam for facility Lesson.objects.create(created_by=superuser, title="lesson", collection=facility) exam = Exam.objects.create(creator=superuser, title="exam", question_count=1, collection=facility) classrooms = user_data.get_or_create_classrooms( n_classes=n_classes, facility=facility) # Get all the user data at once so that it is distinct across classrooms facility_user_data = random.sample(users, n_classes * n_users) # create random content id for the session logs self.content_id = uuid.uuid4().hex for i, classroom in enumerate(classrooms): classroom_user_data = facility_user_data[i * n_users:(i + 1) * n_users] users = user_data.get_or_create_classroom_users( n_users=n_users, classroom=classroom, user_data=classroom_user_data, facility=facility, ) # create 1 of each type of log per user for user in users: for _ in range(1): sessionlog = ContentSessionLog.objects.create( user=user, start_timestamp=min_timestamp, end_timestamp=max_timestamp, content_id=self.content_id, channel_id=self.channel.id, time_spent=60, # 1 minute kind=content_kinds.EXERCISE, ) AttemptLog.objects.create( item="item", start_timestamp=min_timestamp, end_timestamp=max_timestamp, completion_timestamp=max_timestamp, correct=1, sessionlog=sessionlog, ) # create 1 anon log per user session log ContentSessionLog.objects.create( dataset=dataset, user=None, start_timestamp=min_timestamp, end_timestamp=max_timestamp, content_id=self.content_id, channel_id=self.channel.id, time_spent=60, # 1 minute, kind=content_kinds.VIDEO, ) for _ in range(1): UserSessionLog.objects.create( user=user, start_timestamp=min_timestamp, last_interaction_timestamp=max_timestamp, device_info="Android,9/Chrome Mobile,86", ) for _ in range(1): ContentSummaryLog.objects.create( user=user, start_timestamp=min_timestamp, end_timestamp=max_timestamp, completion_timestamp=max_timestamp, content_id=uuid.uuid4().hex, channel_id=self.channel.id, ) for _ in range(1): examlog = ExamLog.objects.create(exam=exam, user=user) ExamAttemptLog.objects.create( examlog=examlog, start_timestamp=min_timestamp, end_timestamp=max_timestamp, completion_timestamp=max_timestamp, correct=1, content_id=uuid.uuid4().hex, )
def handle(self, *args, **options): # Load in the user data from the csv file to give a predictable source of user data data_path = os.path.join(os.path.dirname(__file__), "user_data.csv") with io.open(data_path, mode="r", encoding="utf-8") as f: user_data = [data for data in csv.DictReader(f)] n_seed = options["seed"] n_facilities = options["facilities"] n_users = options["users"] n_classes = options["classes"] no_onboarding = options["no_onboarding"] num_content_items = options["num_content_items"] num_lessons = options["num_lessons"] num_exams = options["num_exams"] max_channels = options["max_channels"] device_name = options["device_name"] # TODO(cpauya): # num_groups = options["num_groups"] # channel_token = options["channel_token"] # TODO(cpauya): Default to the computer/VM name so we get a unique name for each VM automatically. # if not device_name: # # Default to computer name. # # REF: https://stackoverflow.com/questions/4271740/how-can-i-use-python-to-get-the-system-hostname#4271755 # import socket # device_name = socket.gethostname() # utils.logger_info("Defaulting 'device_name' to '{0}'.".format(device_name)) # Set the random seed so that all operations will be randomized predictably random.seed(n_seed) # Generate data up to the current time now = timezone.now() facilities = utils.get_or_create_facilities( n_facilities=n_facilities, device_name=device_name ) # Device needs to be provisioned before adding superusers if no_onboarding: utils.logger_info( "Provisioning device. Onboarding will be skipped after starting server." ) provision_device() for facility in facilities: if no_onboarding: utils.logger_info( 'Creating superuser "superuser" with password "password" at facility {facility}.'.format( facility=facility.name ) ) create_superuser(facility=facility) classrooms = utils.get_or_create_classrooms( n_classes=n_classes, facility=facility, device_name=device_name ) # TODO(cpauya): # if channel_token: # # TODO(cpauya): which table do we get the channel_token field? # channels = ChannelMetadata.objects.filter(channel_token=channel_token) # else: # channels = ChannelMetadata.objects.all()[:max_channels] channels = ChannelMetadata.objects.all() if max_channels and max_channels > 0: channels = channels[:max_channels] if not channels: utils.logger_info( "No channels found, cannot add channel activities for learners." ) # Get all the user data at once so that it is distinct across classrooms facility_user_data = random.sample(user_data, n_classes * n_users) for i, classroom in enumerate(classrooms): classroom_user_data = facility_user_data[ i * n_users : (i + 1) * n_users ] users = utils.get_or_create_classroom_users( n_users=n_users, classroom=classroom, user_data=classroom_user_data, facility=facility, device_name=device_name, ) # Iterate through the slice of the facility_user_data specific to this classroom for user, base_data in zip(users, classroom_user_data): # The user data we are fetching from has 'Age' as a characteristic, use this as the "age" of the user # in terms of their content interaction history - older, more content items interacted with! if num_content_items: n_content_items = num_content_items else: n_content_items = int(base_data["Age"]) # Loop over all local channels to generate data for each channel utils.logger_info(" Learner {learner}...".format(learner=user)) for channel in channels: # TODO(cpauya): check for issue as per Richard's report # REF: https://github.com/learningequality/kolibri/pull/6983#issuecomment-638980072 utils.logger_info( " ==> Adding {channel} channel activity for learner {learner}...".format( channel=channel, learner=user ) ) utils.add_channel_activity_for_user( n_content_items=n_content_items, channel=channel, user=user, now=now, ) # create lessons utils.create_lessons_for_classroom( classroom=classroom, facility=facility, channels=ChannelMetadata.objects.all(), lessons=num_lessons, now=now, ) # create exams utils.create_exams_for_classrooms( classroom=classroom, facility=facility, channels=ChannelMetadata.objects.all(), exams=num_exams, now=now, device_name=device_name, )
def handle(self, *args, **options): # Load in the user data from the csv file to give a predictable source of user data data_path = os.path.join(os.path.dirname(__file__), "user_data.csv") with io.open(data_path, mode="r", encoding="utf-8") as f: user_data = [data for data in csv.DictReader(f)] n_users = options["users"] n_classes = options["classes"] no_onboarding = options["no_onboarding"] num_content_items = options["num_content_items"] num_lessons = options["num_lessons"] num_exams = options["num_exams"] # Set the random seed so that all operations will be randomized predictably random.seed(options["seed"]) # Generate data up to the current time now = timezone.now() facilities = utils.get_or_create_facilities( n_facilities=options["facilities"]) # Device needs to be provisioned before adding superusers if no_onboarding: logger.info( "Provisioning device. Onboarding will be skipped after starting server." ) provision_device() for facility in facilities: if no_onboarding: logger.info( 'Creating superuser "superuser" with password "password" at facility {facility}.' .format(facility=facility.name)) create_superuser(facility=facility) classrooms = utils.get_or_create_classrooms(n_classes=n_classes, facility=facility) # Get all the user data at once so that it is distinct across classrooms facility_user_data = random.sample(user_data, n_classes * n_users) for i, classroom in enumerate(classrooms): classroom_user_data = facility_user_data[i * n_users:(i + 1) * n_users] users = utils.get_or_create_classroom_users( n_users=n_users, classroom=classroom, user_data=classroom_user_data, facility=facility, ) # Iterate through the slice of the facility_user_data specific to this classroom for user, base_data in zip(users, classroom_user_data): # The user data we are fetching from has 'Age' as a characteristic, use this as the "age" of the user # in terms of their content interaction history - older, more content items interacted with! if num_content_items: n_content_items = num_content_items else: n_content_items = int(base_data["Age"]) # Loop over all local channels to generate data for each channel for channel in ChannelMetadata.objects.all(): utils.add_channel_activity_for_user( n_content_items=n_content_items, channel=channel, user=user, now=now, ) # create lessons utils.create_lessons_for_classroom( classroom=classroom, facility=facility, channels=ChannelMetadata.objects.all(), lessons=num_lessons, now=now, ) # create exams utils.create_exams_for_classrooms( classroom=classroom, facility=facility, channels=ChannelMetadata.objects.all(), exams=num_exams, now=now, )