app.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. # -*- coding: utf-8 -*-
  2. """
  3. flaskbb.app
  4. ~~~~~~~~~~~~~~~~~~~~
  5. manages the app creation and configuration process
  6. :copyright: (c) 2014 by the FlaskBB Team.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. import os
  10. import logging
  11. import datetime
  12. from flask import Flask, request
  13. from flask.ext.login import current_user
  14. # Import the user blueprint
  15. from flaskbb.user.views import user
  16. from flaskbb.user.models import User, Guest, PrivateMessage
  17. # Import the auth blueprint
  18. from flaskbb.auth.views import auth
  19. # Import the admin blueprint
  20. from flaskbb.management.views import management
  21. # Import the forum blueprint
  22. from flaskbb.forum.views import forum
  23. from flaskbb.forum.models import Post, Topic, Category, Forum
  24. # extensions
  25. from flaskbb.extensions import db, login_manager, mail, cache, redis, \
  26. debugtoolbar, migrate, themes, plugin_manager
  27. from flask.ext.whooshalchemy import whoosh_index
  28. # various helpers
  29. from flaskbb.utils.helpers import format_date, time_since, crop_title, \
  30. is_online, render_markup, mark_online, forum_is_unread, topic_is_unread, \
  31. render_template
  32. # permission checks (here they are used for the jinja filters)
  33. from flaskbb.utils.permissions import can_post_reply, can_post_topic, \
  34. can_delete_topic, can_delete_post, can_edit_post, can_edit_user, \
  35. can_ban_user, can_moderate, is_admin, is_moderator, is_admin_or_moderator
  36. # app specific configurations
  37. from flaskbb.utils.settings import flaskbb_config
  38. def create_app(config=None):
  39. """
  40. Creates the app.
  41. """
  42. # Initialize the app
  43. app = Flask("flaskbb")
  44. # Use the default config and override it afterwards
  45. app.config.from_object('flaskbb.configs.default.DefaultConfig')
  46. # Update the config
  47. app.config.from_object(config)
  48. # try to update the config via the environment variable
  49. app.config.from_envvar("FLASKBB_SETTINGS", silent=True)
  50. configure_blueprints(app)
  51. configure_extensions(app)
  52. configure_template_filters(app)
  53. configure_context_processors(app)
  54. configure_before_handlers(app)
  55. configure_errorhandlers(app)
  56. configure_logging(app)
  57. return app
  58. def configure_blueprints(app):
  59. app.register_blueprint(forum, url_prefix=app.config["FORUM_URL_PREFIX"])
  60. app.register_blueprint(user, url_prefix=app.config["USER_URL_PREFIX"])
  61. app.register_blueprint(auth, url_prefix=app.config["AUTH_URL_PREFIX"])
  62. app.register_blueprint(management, url_prefix=app.config["ADMIN_URL_PREFIX"])
  63. def configure_extensions(app):
  64. """
  65. Configures the extensions
  66. """
  67. # Flask-Plugins
  68. plugin_manager.init_app(app)
  69. # Flask-SQLAlchemy
  70. db.init_app(app)
  71. # Flask-Migrate
  72. migrate.init_app(app, db)
  73. # Flask-Mail
  74. mail.init_app(app)
  75. # Flask-Cache
  76. cache.init_app(app)
  77. # Flask-Debugtoolbar
  78. debugtoolbar.init_app(app)
  79. # Flask-Themes
  80. themes.init_themes(app, app_identifier="flaskbb")
  81. # Flask-And-Redis
  82. redis.init_app(app)
  83. # Flask-WhooshAlchemy
  84. with app.app_context():
  85. whoosh_index(app, Post)
  86. whoosh_index(app, Topic)
  87. whoosh_index(app, Forum)
  88. whoosh_index(app, Category)
  89. whoosh_index(app, User)
  90. # Flask-Login
  91. login_manager.login_view = app.config["LOGIN_VIEW"]
  92. login_manager.refresh_view = app.config["REAUTH_VIEW"]
  93. login_manager.anonymous_user = Guest
  94. @login_manager.user_loader
  95. def load_user(id):
  96. """
  97. Loads the user. Required by the `login` extension
  98. """
  99. unread_count = db.session.query(db.func.count(PrivateMessage.id)).\
  100. filter(PrivateMessage.unread == True,
  101. PrivateMessage.user_id == id).subquery()
  102. u = db.session.query(User, unread_count).filter(User.id == id).first()
  103. if u:
  104. user, user.pm_unread = u
  105. return user
  106. else:
  107. return None
  108. login_manager.init_app(app)
  109. def configure_template_filters(app):
  110. """
  111. Configures the template filters
  112. """
  113. app.jinja_env.filters['markup'] = render_markup
  114. app.jinja_env.filters['format_date'] = format_date
  115. app.jinja_env.filters['time_since'] = time_since
  116. app.jinja_env.filters['is_online'] = is_online
  117. app.jinja_env.filters['crop_title'] = crop_title
  118. app.jinja_env.filters['forum_is_unread'] = forum_is_unread
  119. app.jinja_env.filters['topic_is_unread'] = topic_is_unread
  120. # Permission filters
  121. app.jinja_env.filters['edit_post'] = can_edit_post
  122. app.jinja_env.filters['delete_post'] = can_delete_post
  123. app.jinja_env.filters['delete_topic'] = can_delete_topic
  124. app.jinja_env.filters['post_reply'] = can_post_reply
  125. app.jinja_env.filters['post_topic'] = can_post_topic
  126. # Moderator permission filters
  127. app.jinja_env.filters['is_admin'] = is_admin
  128. app.jinja_env.filters['is_moderator'] = is_moderator
  129. app.jinja_env.filters['is_admin_or_moderator'] = is_admin_or_moderator
  130. app.jinja_env.filters['can_moderate'] = can_moderate
  131. app.jinja_env.filters['can_edit_user'] = can_edit_user
  132. app.jinja_env.filters['can_ban_user'] = can_ban_user
  133. def configure_context_processors(app):
  134. """
  135. Configures the context processors
  136. """
  137. @app.context_processor
  138. def inject_flaskbb_config():
  139. """
  140. Injects the ``flaskbb_config`` config variable into the templates.
  141. """
  142. return dict(flaskbb_config=flaskbb_config)
  143. def configure_before_handlers(app):
  144. """
  145. Configures the before request handlers
  146. """
  147. @app.before_request
  148. def update_lastseen():
  149. """
  150. Updates `lastseen` before every reguest if the user is authenticated
  151. """
  152. if current_user.is_authenticated():
  153. current_user.lastseen = datetime.datetime.utcnow()
  154. db.session.add(current_user)
  155. db.session.commit()
  156. if app.config["REDIS_ENABLED"]:
  157. @app.before_request
  158. def mark_current_user_online():
  159. if current_user.is_authenticated():
  160. mark_online(current_user.username)
  161. else:
  162. mark_online(request.remote_addr, guest=True)
  163. def configure_errorhandlers(app):
  164. """
  165. Configures the error handlers
  166. """
  167. @app.errorhandler(403)
  168. def forbidden_page(error):
  169. return render_template("errors/forbidden_page.html"), 403
  170. @app.errorhandler(404)
  171. def page_not_found(error):
  172. return render_template("errors/page_not_found.html"), 404
  173. @app.errorhandler(500)
  174. def server_error_page(error):
  175. return render_template("errors/server_error.html"), 500
  176. def configure_logging(app):
  177. """
  178. Configures logging.
  179. """
  180. logs_folder = os.path.join(app.root_path, os.pardir, "logs")
  181. from logging.handlers import SMTPHandler
  182. formatter = logging.Formatter(
  183. '%(asctime)s %(levelname)s: %(message)s '
  184. '[in %(pathname)s:%(lineno)d]')
  185. info_log = os.path.join(logs_folder, app.config['INFO_LOG'])
  186. info_file_handler = logging.handlers.RotatingFileHandler(
  187. info_log,
  188. maxBytes=100000,
  189. backupCount=10
  190. )
  191. info_file_handler.setLevel(logging.INFO)
  192. info_file_handler.setFormatter(formatter)
  193. app.logger.addHandler(info_file_handler)
  194. error_log = os.path.join(logs_folder, app.config['ERROR_LOG'])
  195. error_file_handler = logging.handlers.RotatingFileHandler(
  196. error_log,
  197. maxBytes=100000,
  198. backupCount=10
  199. )
  200. error_file_handler.setLevel(logging.ERROR)
  201. error_file_handler.setFormatter(formatter)
  202. app.logger.addHandler(error_file_handler)
  203. if app.config["SEND_LOGS"]:
  204. mail_handler = \
  205. SMTPHandler(app.config['MAIL_SERVER'],
  206. app.config['MAIL_DEFAULT_SENDER'],
  207. app.config['ADMINS'],
  208. 'application error, no admins specified',
  209. (
  210. app.config['MAIL_USERNAME'],
  211. app.config['MAIL_PASSWORD'],
  212. ))
  213. mail_handler.setLevel(logging.ERROR)
  214. mail_handler.setFormatter(formatter)
  215. app.logger.addHandler(mail_handler)