# -*- coding: utf-8 -*- """ flaskbb.utils.populate ~~~~~~~~~~~~~~~~~~~~~~ A module that makes creating data more easily :copyright: (c) 2014 by the FlaskBB Team. :license: BSD, see LICENSE for more details. """ from __future__ import unicode_literals from sqlalchemy_utils.functions import create_database from flaskbb.management.models import Setting, SettingsGroup from flaskbb.user.models import User, Group from flaskbb.forum.models import Post, Topic, Forum, Category from flaskbb.extensions import alembic, db def delete_settings_from_fixture(fixture): """Deletes the settings from a fixture from the database. Returns the deleted groups and settings. :param fixture: The fixture that should be deleted. """ deleted_settings = {} for settingsgroup in fixture: group = SettingsGroup.query.filter_by(key=settingsgroup[0]).first() deleted_settings[group] = [] for settings in settingsgroup[1]["settings"]: setting = Setting.query.filter_by(key=settings[0]).first() if setting: deleted_settings[group].append(setting) setting.delete() group.delete() return deleted_settings def create_settings_from_fixture(fixture): """Inserts the settings from a fixture into the database. Returns the created groups and settings. :param fixture: The fixture which should inserted. """ created_settings = {} for settingsgroup in fixture: group = SettingsGroup( key=settingsgroup[0], name=settingsgroup[1]["name"], description=settingsgroup[1]["description"] ) group.save() created_settings[group] = [] for settings in settingsgroup[1]["settings"]: setting = Setting( key=settings[0], value=settings[1]["value"], value_type=settings[1]["value_type"], name=settings[1]["name"], description=settings[1]["description"], extra=settings[1].get("extra", ""), # Optional field settingsgroup=group.key ) if setting: setting.save() created_settings[group].append(setting) return created_settings def update_settings_from_fixture(fixture, overwrite_group=False, overwrite_setting=False): """Updates the database settings from a fixture. Returns the updated groups and settings. :param fixture: The fixture which should be inserted/updated. :param overwrite_group: Set this to ``True`` if you want to overwrite the group if it already exists. Defaults to ``False``. :param overwrite_setting: Set this to ``True`` if you want to overwrite the setting if it already exists. Defaults to ``False``. """ updated_settings = {} for settingsgroup in fixture: group = SettingsGroup.query.filter_by(key=settingsgroup[0]).first() if (group is not None and overwrite_group) or group is None: if group is not None: group.name = settingsgroup[1]["name"] group.description = settingsgroup[1]["description"] else: group = SettingsGroup( key=settingsgroup[0], name=settingsgroup[1]["name"], description=settingsgroup[1]["description"] ) group.save() for settings in settingsgroup[1]["settings"]: setting = Setting.query.filter_by(key=settings[0]).first() if (setting is not None and overwrite_setting) or setting is None: if setting is not None: setting.value = settings[1]["value"] setting.value_type = settings[1]["value_type"] setting.name = settings[1]["name"] setting.description = settings[1]["description"] setting.extra = settings[1].get("extra", "") setting.settingsgroup = group.key else: setting = Setting( key=settings[0], value=settings[1]["value"], value_type=settings[1]["value_type"], name=settings[1]["name"], description=settings[1]["description"], extra=settings[1].get("extra", ""), settingsgroup=group.key ) setting.save() updated_settings[group] = [] updated_settings[group].append(setting) return updated_settings def create_default_settings(): """Creates the default settings.""" from flaskbb.fixtures.settings import fixture create_settings_from_fixture(fixture) def create_default_groups(): """This will create the 5 default groups.""" from flaskbb.fixtures.groups import fixture result = [] for key, value in fixture.items(): group = Group(name=key) for k, v in value.items(): setattr(group, k, v) group.save() result.append(group) return result def create_user(username, password, email, groupname): """Creates a user. Returns the created user. :param username: The username of the user. :param password: The password of the user. :param email: The email address of the user. :param groupname: The name of the group to which the user should belong to. """ if groupname == "member": group = Group.get_member_group() else: group = Group.query.filter(getattr(Group, groupname) == True).first() user = User.create(username=username, password=password, email=email, primary_group_id=group.id, activated=True) return user def update_user(username, password, email, groupname): """Update an existing user. Returns the updated user. :param username: The username of the user. :param password: The password of the user. :param email: The email address of the user. :param groupname: The name of the group to which the user should belong to. """ user = User.query.filter_by(username=username).first() if user is None: return None if groupname == "member": group = Group.get_member_group() else: group = Group.query.filter(getattr(Group, groupname) == True).first() user.password = password user.email = email user.primary_group = group return user.save() def create_welcome_forum(): """This will create the `welcome forum` with a welcome topic. Returns True if it's created successfully. """ if User.query.count() < 1: return False user = User.query.filter_by(id=1).first() category = Category(title="My Category", position=1) category.save() forum = Forum(title="Welcome", description="Your first forum", category_id=category.id) forum.save() topic = Topic(title="Welcome!") post = Post(content="Have fun with your new FlaskBB Forum!") topic.save(user=user, forum=forum, post=post) return True def create_test_data(users=5, categories=2, forums=2, topics=1, posts=1): """Creates 5 users, 2 categories and 2 forums in each category. It also creates a new topic topic in each forum with a post. Returns the amount of created users, categories, forums, topics and posts as a dict. :param users: The number of users. :param categories: The number of categories. :param forums: The number of forums which are created in each category. :param topics: The number of topics which are created in each forum. :param posts: The number of posts which are created in each topic. """ create_default_groups() create_default_settings() data_created = {'users': 0, 'categories': 0, 'forums': 0, 'topics': 0, 'posts': 0} # create 5 users for u in range(1, users + 1): username = "test%s" % u email = "test%s@example.org" % u user = User(username=username, password="test", email=email) user.primary_group_id = u user.activated = True user.save() data_created['users'] += 1 user1 = User.query.filter_by(id=1).first() user2 = User.query.filter_by(id=2).first() # lets send them a few private messages for i in range(1, 3): # TODO pass # create 2 categories for i in range(1, categories + 1): category_title = "Test Category %s" % i category = Category(title=category_title, description="Test Description") category.save() data_created['categories'] += 1 # create 2 forums in each category for j in range(1, forums + 1): if i == 2: j += 2 forum_title = "Test Forum %s %s" % (j, i) forum = Forum(title=forum_title, description="Test Description", category_id=i) forum.save() data_created['forums'] += 1 for t in range(1, topics + 1): # create a topic topic = Topic(title="Test Title %s" % j) post = Post(content="Test Content") topic.save(post=post, user=user1, forum=forum) data_created['topics'] += 1 for p in range(1, posts + 1): # create a second post in the forum post = Post(content="Test Post") post.save(user=user2, topic=topic) data_created['posts'] += 1 return data_created def insert_bulk_data(topic_count=10, post_count=100): """Creates a specified number of topics in the first forum with each topic containing a specified amount of posts. Returns the number of created topics and posts. :param topics: The amount of topics in the forum. :param posts: The number of posts in each topic. """ user1 = User.query.filter_by(id=1).first() user2 = User.query.filter_by(id=2).first() forum = Forum.query.filter_by(id=1).first() last_post = Post.query.order_by(Post.id.desc()).first() last_post_id = 1 if last_post is None else last_post.id created_posts = 0 created_topics = 0 posts = [] if not (user1 or user2 or forum): return False db.session.begin(subtransactions=True) for i in range(1, topic_count + 1): last_post_id += 1 # create a topic topic = Topic(title="Test Title %s" % i) post = Post(content="First Post") topic.save(post=post, user=user1, forum=forum) created_topics += 1 # create some posts in the topic for j in range(1, post_count + 1): last_post_id += 1 post = Post(content="Some other Post", user=user2, topic=topic.id) topic.last_updated = post.date_created topic.post_count += 1 # FIXME: Is there a way to ignore IntegrityErrors? # At the moment, the first_post_id is also the last_post_id. # This does no harm, except that in the forums view, you see # the information for the first post instead of the last one. # I run a little benchmark: # 5.3643078804 seconds to create 100 topics and 10000 posts # Using another method (where data integrity is ok) I benchmarked # these stats: # 49.7832770348 seconds to create 100 topics and 10000 posts # Uncomment the line underneath and the other line to reduce # performance but fixes the above mentioned problem. # topic.last_post_id = last_post_id created_posts += 1 posts.append(post) # uncomment this and delete the one below, also uncomment the # topic.last_post_id line above. This will greatly reduce the # performance. # db.session.bulk_save_objects(posts) db.session.bulk_save_objects(posts) # and finally, lets update some stats forum.recalculate(last_post=True) user1.recalculate() user2.recalculate() return created_topics, created_posts def create_latest_db(): """Creates the database including the schema using SQLAlchemy's db.create_all method instead of going through all the database revisions. The revision will be set to 'head' which indicates the latest alembic revision. """ create_database(db.engine.url) db.create_all() alembic.stamp()