populate.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. # -*- coding: utf-8 -*-
  2. """
  3. flaskbb.utils.populate
  4. ~~~~~~~~~~~~~~~~~~~~~~
  5. A module that makes creating data more easily
  6. :copyright: (c) 2014 by the FlaskBB Team.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. from __future__ import unicode_literals
  10. from flaskbb.management.models import Setting, SettingsGroup
  11. from flaskbb.user.models import User, Group
  12. from flaskbb.forum.models import Post, Topic, Forum, Category
  13. from flaskbb.extensions import db
  14. def delete_settings_from_fixture(fixture):
  15. """Deletes the settings from a fixture from the database.
  16. Returns the deleted groups and settings.
  17. :param fixture: The fixture that should be deleted.
  18. """
  19. deleted_settings = {}
  20. for settingsgroup in fixture:
  21. group = SettingsGroup.query.filter_by(key=settingsgroup[0]).first()
  22. deleted_settings[group] = []
  23. for settings in settingsgroup[1]["settings"]:
  24. setting = Setting.query.filter_by(key=settings[0]).first()
  25. if setting:
  26. deleted_settings[group].append(setting)
  27. setting.delete()
  28. group.delete()
  29. return deleted_settings
  30. def create_settings_from_fixture(fixture):
  31. """Inserts the settings from a fixture into the database.
  32. Returns the created groups and settings.
  33. :param fixture: The fixture which should inserted.
  34. """
  35. created_settings = {}
  36. for settingsgroup in fixture:
  37. group = SettingsGroup(
  38. key=settingsgroup[0],
  39. name=settingsgroup[1]["name"],
  40. description=settingsgroup[1]["description"]
  41. )
  42. group.save()
  43. created_settings[group] = []
  44. for settings in settingsgroup[1]["settings"]:
  45. setting = Setting(
  46. key=settings[0],
  47. value=settings[1]["value"],
  48. value_type=settings[1]["value_type"],
  49. name=settings[1]["name"],
  50. description=settings[1]["description"],
  51. extra=settings[1].get("extra", ""), # Optional field
  52. settingsgroup=group.key
  53. )
  54. if setting:
  55. setting.save()
  56. created_settings[group].append(setting)
  57. return created_settings
  58. def update_settings_from_fixture(fixture, overwrite_group=False,
  59. overwrite_setting=False):
  60. """Updates the database settings from a fixture.
  61. Returns the updated groups and settings.
  62. :param fixture: The fixture which should be inserted/updated.
  63. :param overwrite_group: Set this to ``True`` if you want to overwrite
  64. the group if it already exists.
  65. Defaults to ``False``.
  66. :param overwrite_setting: Set this to ``True`` if you want to overwrite the
  67. setting if it already exists.
  68. Defaults to ``False``.
  69. """
  70. updated_settings = {}
  71. for settingsgroup in fixture:
  72. group = SettingsGroup.query.filter_by(key=settingsgroup[0]).first()
  73. if (group is not None and overwrite_group) or group is None:
  74. if group is not None:
  75. group.name = settingsgroup[1]["name"]
  76. group.description = settingsgroup[1]["description"]
  77. else:
  78. group = SettingsGroup(
  79. key=settingsgroup[0],
  80. name=settingsgroup[1]["name"],
  81. description=settingsgroup[1]["description"]
  82. )
  83. group.save()
  84. updated_settings[group] = []
  85. for settings in settingsgroup[1]["settings"]:
  86. setting = Setting.query.filter_by(key=settings[0]).first()
  87. if (setting is not None and overwrite_setting) or setting is None:
  88. if setting is not None:
  89. setting.value = settings[1]["value"]
  90. setting.value_type = settings[1]["value_type"]
  91. setting.name = settings[1]["name"]
  92. setting.description = settings[1]["description"]
  93. setting.extra = settings[1].get("extra", "")
  94. setting.settingsgroup = group.key
  95. else:
  96. setting = Setting(
  97. key=settings[0],
  98. value=settings[1]["value"],
  99. value_type=settings[1]["value_type"],
  100. name=settings[1]["name"],
  101. description=settings[1]["description"],
  102. extra=settings[1].get("extra", ""),
  103. settingsgroup=group.key
  104. )
  105. setting.save()
  106. updated_settings[group].append(setting)
  107. return updated_settings
  108. def create_default_settings():
  109. """Creates the default settings."""
  110. from flaskbb.fixtures.settings import fixture
  111. create_settings_from_fixture(fixture)
  112. def create_default_groups():
  113. """This will create the 5 default groups."""
  114. from flaskbb.fixtures.groups import fixture
  115. result = []
  116. for key, value in fixture.items():
  117. group = Group(name=key)
  118. for k, v in value.items():
  119. setattr(group, k, v)
  120. group.save()
  121. result.append(group)
  122. return result
  123. def create_user(username, password, email, groupname):
  124. """Creates a user.
  125. Returns the created user.
  126. :param username: The username of the user.
  127. :param password: The password of the user.
  128. :param email: The email address of the user.
  129. :param groupname: The name of the group to which the user
  130. should belong to.
  131. """
  132. if groupname == "member":
  133. group = Group.get_member_group()
  134. else:
  135. group = Group.query.filter(getattr(Group, groupname) == True).first()
  136. user = User.create(username=username, password=password, email=email,
  137. primary_group_id=group.id, activated=True)
  138. return user
  139. def update_user(username, password, email, groupname):
  140. """Update an existing user.
  141. Returns the updated user.
  142. :param username: The username of the user.
  143. :param password: The password of the user.
  144. :param email: The email address of the user.
  145. :param groupname: The name of the group to which the user
  146. should belong to.
  147. """
  148. user = User.query.filter_by(username=username).first()
  149. if user is None:
  150. return None
  151. if groupname == "member":
  152. group = Group.get_member_group()
  153. else:
  154. group = Group.query.filter(getattr(Group, groupname) == True).first()
  155. user.password = password
  156. user.email = email
  157. user.primary_group_id = group.id
  158. return user.save()
  159. def create_welcome_forum():
  160. """This will create the `welcome forum` with a welcome topic.
  161. Returns True if it's created successfully.
  162. """
  163. if User.query.count() < 1:
  164. return False
  165. user = User.query.filter_by(id=1).first()
  166. category = Category(title="My Category", position=1)
  167. category.save()
  168. forum = Forum(title="Welcome", description="Your first forum",
  169. category_id=category.id)
  170. forum.save()
  171. topic = Topic(title="Welcome!")
  172. post = Post(content="Have fun with your new FlaskBB Forum!")
  173. topic.save(user=user, forum=forum, post=post)
  174. return True
  175. def create_test_data(users=5, categories=2, forums=2, topics=1, posts=1):
  176. """Creates 5 users, 2 categories and 2 forums in each category.
  177. It also creates a new topic topic in each forum with a post.
  178. Returns the amount of created users, categories, forums, topics and posts
  179. as a dict.
  180. :param users: The number of users.
  181. :param categories: The number of categories.
  182. :param forums: The number of forums which are created in each category.
  183. :param topics: The number of topics which are created in each forum.
  184. :param posts: The number of posts which are created in each topic.
  185. """
  186. create_default_groups()
  187. create_default_settings()
  188. data_created = {'users': 0, 'categories': 0, 'forums': 0,
  189. 'topics': 0, 'posts': 0}
  190. # create 5 users
  191. for u in range(1, users + 1):
  192. username = "test%s" % u
  193. email = "test%s@example.org" % u
  194. user = User(username=username, password="test", email=email)
  195. user.primary_group_id = u
  196. user.activated = True
  197. user.save()
  198. data_created['users'] += 1
  199. user1 = User.query.filter_by(id=1).first()
  200. user2 = User.query.filter_by(id=2).first()
  201. # lets send them a few private messages
  202. for i in range(1, 3):
  203. # TODO
  204. pass
  205. # create 2 categories
  206. for i in range(1, categories + 1):
  207. category_title = "Test Category %s" % i
  208. category = Category(title=category_title,
  209. description="Test Description")
  210. category.save()
  211. data_created['categories'] += 1
  212. # create 2 forums in each category
  213. for j in range(1, forums + 1):
  214. if i == 2:
  215. j += 2
  216. forum_title = "Test Forum %s %s" % (j, i)
  217. forum = Forum(title=forum_title, description="Test Description",
  218. category_id=i)
  219. forum.save()
  220. data_created['forums'] += 1
  221. for t in range(1, topics + 1):
  222. # create a topic
  223. topic = Topic(title="Test Title %s" % j)
  224. post = Post(content="Test Content")
  225. topic.save(post=post, user=user1, forum=forum)
  226. data_created['topics'] += 1
  227. for p in range(1, posts + 1):
  228. # create a second post in the forum
  229. post = Post(content="Test Post")
  230. post.save(user=user2, topic=topic)
  231. data_created['posts'] += 1
  232. return data_created
  233. def insert_bulk_data(topic_count=10, post_count=100):
  234. """Creates a specified number of topics in the first forum with
  235. each topic containing a specified amount of posts.
  236. Returns the number of created topics and posts.
  237. :param topics: The amount of topics in the forum.
  238. :param posts: The number of posts in each topic.
  239. """
  240. user1 = User.query.filter_by(id=1).first()
  241. user2 = User.query.filter_by(id=2).first()
  242. forum = Forum.query.filter_by(id=1).first()
  243. last_post = Post.query.order_by(Post.id.desc()).first()
  244. last_post_id = 1 if last_post is None else last_post.id
  245. created_posts = 0
  246. created_topics = 0
  247. posts = []
  248. if not (user1 or user2 or forum):
  249. return False
  250. db.session.begin(subtransactions=True)
  251. for i in range(1, topic_count + 1):
  252. last_post_id += 1
  253. # create a topic
  254. topic = Topic(title="Test Title %s" % i)
  255. post = Post(content="First Post")
  256. topic.save(post=post, user=user1, forum=forum)
  257. created_topics += 1
  258. # create some posts in the topic
  259. for j in range(1, post_count + 1):
  260. last_post_id += 1
  261. post = Post(content="Some other Post", user=user2, topic=topic.id)
  262. topic.last_updated = post.date_created
  263. topic.post_count += 1
  264. # FIXME: Is there a way to ignore IntegrityErrors?
  265. # At the moment, the first_post_id is also the last_post_id.
  266. # This does no harm, except that in the forums view, you see
  267. # the information for the first post instead of the last one.
  268. # I run a little benchmark:
  269. # 5.3643078804 seconds to create 100 topics and 10000 posts
  270. # Using another method (where data integrity is ok) I benchmarked
  271. # these stats:
  272. # 49.7832770348 seconds to create 100 topics and 10000 posts
  273. # Uncomment the line underneath and the other line to reduce
  274. # performance but fixes the above mentioned problem.
  275. #topic.last_post_id = last_post_id
  276. created_posts += 1
  277. posts.append(post)
  278. # uncomment this and delete the one below, also uncomment the
  279. # topic.last_post_id line above. This will greatly reduce the
  280. # performance.
  281. #db.session.bulk_save_objects(posts)
  282. db.session.bulk_save_objects(posts)
  283. # and finally, lets update some stats
  284. forum.recalculate(last_post=True)
  285. user1.recalculate()
  286. user2.recalculate()
  287. return created_topics, created_posts