manage.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. #!/usr/bin/env python
  2. """
  3. flaskbb.manage
  4. ~~~~~~~~~~~~~~~~~~~~
  5. This script provides some easy to use commands for
  6. creating the database with or without some sample content.
  7. You can also run the development server with it.
  8. Just type `python manage.py` to see the full list of commands.
  9. TODO: When Flask 1.0 is released, get rid of Flask-Script and use click.
  10. Then it's also possible to split the commands in "command groups"
  11. which would make the commands better seperated from each other
  12. and less confusing.
  13. :copyright: (c) 2014 by the FlaskBB Team.
  14. :license: BSD, see LICENSE for more details.
  15. """
  16. import sys
  17. import os
  18. import subprocess
  19. import requests
  20. from flask import current_app
  21. from werkzeug.utils import import_string
  22. from sqlalchemy.exc import IntegrityError, OperationalError
  23. from flask_script import (Manager, Shell, Server, prompt, prompt_pass,
  24. prompt_bool)
  25. from flask_migrate import MigrateCommand, upgrade
  26. from flaskbb import create_app
  27. from flaskbb.extensions import db, plugin_manager
  28. from flaskbb.utils.populate import (create_test_data, create_welcome_forum,
  29. create_admin_user, create_default_groups,
  30. create_default_settings, insert_mass_data,
  31. update_settings_from_fixture)
  32. # Use the development configuration if available
  33. try:
  34. from flaskbb.configs.development import DevelopmentConfig as Config
  35. except ImportError:
  36. from flaskbb.configs.default import DefaultConfig as Config
  37. app = create_app(Config)
  38. manager = Manager(app)
  39. # Used to get the plugin translations
  40. PLUGINS_FOLDER = os.path.join(app.root_path, "plugins")
  41. # Run local server
  42. manager.add_command("runserver", Server("localhost", port=8080))
  43. # Migration commands
  44. manager.add_command('db', MigrateCommand)
  45. # Add interactive project shell
  46. def make_shell_context():
  47. return dict(app=current_app, db=db)
  48. manager.add_command("shell", Shell(make_context=make_shell_context))
  49. @manager.command
  50. def initdb():
  51. """Creates the database."""
  52. upgrade()
  53. @manager.command
  54. def dropdb():
  55. """Deletes the database."""
  56. db.drop_all()
  57. @manager.command
  58. def populate(dropdb=False, createdb=False):
  59. """Creates the database with some default data.
  60. If you do not want to drop or create the db add
  61. '-c' (to not create the db) and '-d' (to not drop the db)
  62. """
  63. if not dropdb:
  64. app.logger.info("Dropping database...")
  65. db.drop_all()
  66. if not createdb:
  67. app.logger.info("Creating database...")
  68. upgrade()
  69. app.logger.info("Creating test data...")
  70. create_test_data()
  71. @manager.option('-u', '--username', dest='username')
  72. @manager.option('-p', '--password', dest='password')
  73. @manager.option('-e', '--email', dest='email')
  74. def create_admin(username=None, password=None, email=None):
  75. """Creates the admin user."""
  76. if not (username and password and email):
  77. username = prompt("Username")
  78. email = prompt("A valid email address")
  79. password = prompt_pass("Password")
  80. create_admin_user(username=username, password=password, email=email)
  81. @manager.option('-u', '--username', dest='username')
  82. @manager.option('-p', '--password', dest='password')
  83. @manager.option('-e', '--email', dest='email')
  84. def init(username=None, password=None, email=None):
  85. """Initializes FlaskBB with all necessary data."""
  86. app.logger.info("Creating default data...")
  87. try:
  88. create_default_groups()
  89. create_default_settings()
  90. except IntegrityError:
  91. app.logger.error("Couldn't create the default data because it already "
  92. "exist!")
  93. if prompt_bool("Found an existing database."
  94. "Do you want to recreate the database? (y/n)"):
  95. db.session.rollback()
  96. db.drop_all()
  97. upgrade()
  98. create_default_groups()
  99. create_default_settings()
  100. else:
  101. sys.exit(0)
  102. except OperationalError:
  103. app.logger.error("No database found.")
  104. if prompt_bool("Do you want to create the database now? (y/n)"):
  105. db.session.rollback()
  106. upgrade()
  107. create_default_groups()
  108. create_default_settings()
  109. else:
  110. sys.exit(0)
  111. app.logger.info("Creating admin user...")
  112. if username and password and email:
  113. create_admin_user(username=username, password=password, email=email)
  114. else:
  115. create_admin()
  116. app.logger.info("Creating welcome forum...")
  117. create_welcome_forum()
  118. app.logger.info("Compiling translations...")
  119. compile_translations()
  120. app.logger.info("Congratulations! FlaskBB has been successfully installed")
  121. @manager.command
  122. def insertmassdata():
  123. """Warning: This can take a long time!.
  124. Creates 100 topics and each topic contains 100 posts.
  125. """
  126. insert_mass_data()
  127. @manager.option('-s', '--settings', dest="settings")
  128. @manager.option('-f', '--force', dest="force", default=False)
  129. def update(settings=None, force=False):
  130. """Updates the settings via a fixture. All fixtures have to be placed
  131. in the `fixture`.
  132. Usage: python manage.py update -s your_fixture
  133. """
  134. try:
  135. fixture = import_string(
  136. "flaskbb.fixtures.{}".format(settings)
  137. )
  138. fixture = fixture.fixture
  139. except ImportError:
  140. raise "{} fixture is not available".format(settings)
  141. if force:
  142. count = update_settings_from_fixture(fixture, overwrite_group=True,
  143. overwrite_setting=True)
  144. app.logger.info(
  145. "{} groups and {} settings forcefully updated."
  146. .format(count[0], count[1])
  147. )
  148. else:
  149. count = update_settings_from_fixture(fixture)
  150. app.logger.info(
  151. "{} groups and {} settings updated.".format(count[0], count[1])
  152. )
  153. @manager.command
  154. def update_translations():
  155. """Updates all translations."""
  156. # update flaskbb translations
  157. translations_folder = os.path.join(app.root_path, "translations")
  158. source_file = os.path.join(translations_folder, "messages.pot")
  159. subprocess.call(["pybabel", "extract", "-F", "babel.cfg",
  160. "-k", "lazy_gettext", "-o", source_file, "."])
  161. subprocess.call(["pybabel", "update", "-i", source_file,
  162. "-d", translations_folder])
  163. # updates all plugin translations too
  164. for plugin in plugin_manager.all_plugins:
  165. update_plugin_translations(plugin)
  166. @manager.command
  167. def add_translations(translation):
  168. """Adds a new language to the translations."""
  169. translations_folder = os.path.join(app.root_path, "translations")
  170. source_file = os.path.join(translations_folder, "messages.pot")
  171. subprocess.call(["pybabel", "extract", "-F", "babel.cfg",
  172. "-k", "lazy_gettext", "-o", source_file, "."])
  173. subprocess.call(["pybabel", "init", "-i", source_file,
  174. "-d", translations_folder, "-l", translation])
  175. @manager.command
  176. def compile_translations():
  177. """Compiles all translations."""
  178. # compile flaskbb translations
  179. translations_folder = os.path.join(app.root_path, "translations")
  180. subprocess.call(["pybabel", "compile", "-d", translations_folder])
  181. # compile all plugin translations
  182. for plugin in plugin_manager.all_plugins:
  183. compile_plugin_translations(plugin)
  184. # Plugin translation commands
  185. @manager.command
  186. def add_plugin_translations(plugin, translation):
  187. """Adds a new language to the plugin translations. Expects the name
  188. of the plugin and the translations name like "en".
  189. """
  190. plugin_folder = os.path.join(PLUGINS_FOLDER, plugin)
  191. translations_folder = os.path.join(plugin_folder, "translations")
  192. source_file = os.path.join(translations_folder, "messages.pot")
  193. subprocess.call(["pybabel", "extract", "-F", "babel.cfg",
  194. "-k", "lazy_gettext", "-o", source_file,
  195. plugin_folder])
  196. subprocess.call(["pybabel", "init", "-i", source_file,
  197. "-d", translations_folder, "-l", translation])
  198. @manager.command
  199. def update_plugin_translations(plugin):
  200. """Updates the plugin translations. Expects the name of the plugin."""
  201. plugin_folder = os.path.join(PLUGINS_FOLDER, plugin)
  202. translations_folder = os.path.join(plugin_folder, "translations")
  203. source_file = os.path.join(translations_folder, "messages.pot")
  204. subprocess.call(["pybabel", "extract", "-F", "babel.cfg",
  205. "-k", "lazy_gettext", "-o", source_file,
  206. plugin_folder])
  207. subprocess.call(["pybabel", "update", "-i", source_file,
  208. "-d", translations_folder])
  209. @manager.command
  210. def compile_plugin_translations(plugin):
  211. """Compile the plugin translations. Expects the name of the plugin."""
  212. plugin_folder = os.path.join(PLUGINS_FOLDER, plugin)
  213. translations_folder = os.path.join(plugin_folder, "translations")
  214. subprocess.call(["pybabel", "compile", "-d", translations_folder])
  215. @manager.command
  216. def download_emoji():
  217. """Downloads emojis from emoji-cheat-sheet.com."""
  218. HOSTNAME = "https://api.github.com"
  219. REPO = "/repos/arvida/emoji-cheat-sheet.com/contents/public/graphics/emojis"
  220. FULL_URL = "{}{}".format(HOSTNAME, REPO)
  221. DOWNLOAD_PATH = os.path.join(app.static_folder, "emoji")
  222. response = requests.get(FULL_URL)
  223. for image in response.json():
  224. if not os.path.exists(os.path.abspath(DOWNLOAD_PATH)):
  225. print "%s does not exist." % os.path.abspath(DOWNLOAD_PATH)
  226. sys.exit(1)
  227. full_path = os.path.join(DOWNLOAD_PATH, image["name"])
  228. f = open(full_path, 'wb')
  229. f.write(requests.get(image["download_url"]).content)
  230. f.close()
  231. if __name__ == "__main__":
  232. manager.run()