app.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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, render_template, 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.admin.views import admin
  21. # Import the forum blueprint
  22. from flaskbb.forum.views import forum
  23. from flaskbb.extensions import (db, login_manager, mail, cache, redis,
  24. debugtoolbar, migrate)
  25. from flaskbb.utils.helpers import (format_date, time_since, crop_title,
  26. can_post_reply, can_post_topic,
  27. can_delete_topic, can_delete_post, is_online,
  28. can_edit_post, can_lock_topic,
  29. can_move_topic, render_markup, mark_online,
  30. forum_is_unread, topic_is_unread)
  31. def create_app(config=None):
  32. """
  33. Creates the app.
  34. """
  35. # Initialize the app
  36. app = Flask("flaskbb")
  37. # Use the default config and override it afterwards
  38. app.config.from_object('flaskbb.configs.default.DefaultConfig')
  39. # Update the config
  40. app.config.from_object(config)
  41. # try to update the config via the environment variable
  42. app.config.from_envvar("FLASKBB_SETTINGS", silent=True)
  43. configure_blueprints(app)
  44. configure_extensions(app)
  45. configure_template_filters(app)
  46. configure_before_handlers(app)
  47. configure_errorhandlers(app)
  48. configure_logging(app)
  49. return app
  50. def configure_blueprints(app):
  51. app.register_blueprint(forum, url_prefix=app.config["FORUM_URL_PREFIX"])
  52. app.register_blueprint(user, url_prefix=app.config["USER_URL_PREFIX"])
  53. app.register_blueprint(auth, url_prefix=app.config["AUTH_URL_PREFIX"])
  54. app.register_blueprint(admin, url_prefix=app.config["ADMIN_URL_PREFIX"])
  55. def configure_extensions(app):
  56. """
  57. Configures the extensions
  58. """
  59. # Flask-SQLAlchemy
  60. db.init_app(app)
  61. # Flask-Migrate
  62. migrate.init_app(app, db)
  63. # Flask-Mail
  64. mail.init_app(app)
  65. # Flask-Cache
  66. cache.init_app(app)
  67. # Flask-Debugtoolbar
  68. debugtoolbar.init_app(app)
  69. # Flask-And-Redis
  70. redis.init_app(app)
  71. # Flask-Login
  72. login_manager.login_view = app.config["LOGIN_VIEW"]
  73. login_manager.refresh_view = app.config["REAUTH_VIEW"]
  74. login_manager.anonymous_user = Guest
  75. @login_manager.user_loader
  76. def load_user(id):
  77. """
  78. Loads the user. Required by the `login` extension
  79. """
  80. unread_count = db.session.query(db.func.count(PrivateMessage.id)).\
  81. filter(PrivateMessage.unread == True,
  82. PrivateMessage.user_id == id).subquery()
  83. u = db.session.query(User, unread_count).filter(User.id == id).first()
  84. if u:
  85. user, user.pm_unread = u
  86. return user
  87. else:
  88. return None
  89. login_manager.init_app(app)
  90. def configure_template_filters(app):
  91. """
  92. Configures the template filters
  93. """
  94. app.jinja_env.filters['markup'] = render_markup
  95. app.jinja_env.filters['format_date'] = format_date
  96. app.jinja_env.filters['time_since'] = time_since
  97. app.jinja_env.filters['is_online'] = is_online
  98. app.jinja_env.filters['crop_title'] = crop_title
  99. app.jinja_env.filters['forum_is_unread'] = forum_is_unread
  100. app.jinja_env.filters['topic_is_unread'] = topic_is_unread
  101. # Permission filters
  102. app.jinja_env.filters['edit_post'] = can_edit_post
  103. app.jinja_env.filters['delete_post'] = can_delete_post
  104. app.jinja_env.filters['delete_topic'] = can_delete_topic
  105. app.jinja_env.filters['move_topic'] = can_move_topic
  106. app.jinja_env.filters['lock_topic'] = can_lock_topic
  107. app.jinja_env.filters['post_reply'] = can_post_reply
  108. app.jinja_env.filters['post_topic'] = can_post_topic
  109. def configure_before_handlers(app):
  110. """
  111. Configures the before request handlers
  112. """
  113. @app.before_request
  114. def update_lastseen():
  115. """
  116. Updates `lastseen` before every reguest if the user is authenticated
  117. """
  118. if current_user.is_authenticated():
  119. current_user.lastseen = datetime.datetime.utcnow()
  120. db.session.add(current_user)
  121. db.session.commit()
  122. @app.before_request
  123. def get_user_permissions():
  124. current_user.permissions = current_user.get_permissions()
  125. if app.config["REDIS_ENABLED"]:
  126. @app.before_request
  127. def mark_current_user_online():
  128. if current_user.is_authenticated():
  129. mark_online(current_user.username)
  130. else:
  131. mark_online(request.remote_addr, guest=True)
  132. def configure_errorhandlers(app):
  133. """
  134. Configures the error handlers
  135. """
  136. @app.errorhandler(403)
  137. def forbidden_page(error):
  138. return render_template("errors/forbidden_page.html"), 403
  139. @app.errorhandler(404)
  140. def page_not_found(error):
  141. return render_template("errors/page_not_found.html"), 404
  142. @app.errorhandler(500)
  143. def server_error_page(error):
  144. return render_template("errors/server_error.html"), 500
  145. def configure_logging(app):
  146. """
  147. Configures logging.
  148. """
  149. logs_folder = os.path.join(app.root_path, os.pardir, "logs")
  150. from logging.handlers import SMTPHandler
  151. formatter = logging.Formatter(
  152. '%(asctime)s %(levelname)s: %(message)s '
  153. '[in %(pathname)s:%(lineno)d]')
  154. info_log = os.path.join(logs_folder, app.config['INFO_LOG'])
  155. info_file_handler = logging.handlers.RotatingFileHandler(
  156. info_log,
  157. maxBytes=100000,
  158. backupCount=10
  159. )
  160. info_file_handler.setLevel(logging.INFO)
  161. info_file_handler.setFormatter(formatter)
  162. app.logger.addHandler(info_file_handler)
  163. error_log = os.path.join(logs_folder, app.config['ERROR_LOG'])
  164. error_file_handler = logging.handlers.RotatingFileHandler(
  165. error_log,
  166. maxBytes=100000,
  167. backupCount=10
  168. )
  169. error_file_handler.setLevel(logging.ERROR)
  170. error_file_handler.setFormatter(formatter)
  171. app.logger.addHandler(error_file_handler)
  172. if app.config["SEND_LOGS"]:
  173. mail_handler = \
  174. SMTPHandler(app.config['MAIL_SERVER'],
  175. app.config['DEFAULT_MAIL_SENDER'],
  176. app.config['ADMINS'],
  177. 'application error, no admins specified',
  178. (
  179. app.config['MAIL_USERNAME'],
  180. app.config['MAIL_PASSWORD'],
  181. ))
  182. mail_handler.setLevel(logging.ERROR)
  183. mail_handler.setFormatter(formatter)
  184. app.logger.addHandler(mail_handler)