A Python content management system designed for kirsle.net featuring a blog, comments and photo albums. https://rophako.kirsle.net/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

160 lines
4.7 KiB

  1. from flask import Flask, g, request, session, render_template, send_file, abort
  2. from flask_sslify import SSLify
  3. import jinja2
  4. import os.path
  5. import time
  6. import sys
  7. import config
  8. from rophako import __version__
  9. import rophako.utils
  10. app = Flask(__name__,
  11. static_url_path="/.static",
  12. )
  13. app.DEBUG = config.DEBUG
  14. app.secret_key = config.SECRET_KEY
  15. # Security?
  16. if config.FORCE_SSL:
  17. app.config['SESSION_COOKIE_SECURE'] = True
  18. sslify = SSLify(app)
  19. # Load all the blueprints!
  20. from rophako.modules.admin import mod as AdminModule
  21. from rophako.modules.account import mod as AccountModule
  22. from rophako.modules.blog import mod as BlogModule
  23. from rophako.modules.photo import mod as PhotoModule
  24. from rophako.modules.comment import mod as CommentModule
  25. from rophako.modules.emoticons import mod as EmoticonsModule
  26. from rophako.modules.contact import mod as ContactModule
  27. app.register_blueprint(AdminModule)
  28. app.register_blueprint(AccountModule)
  29. app.register_blueprint(BlogModule)
  30. app.register_blueprint(PhotoModule)
  31. app.register_blueprint(CommentModule)
  32. app.register_blueprint(EmoticonsModule)
  33. app.register_blueprint(ContactModule)
  34. # Custom Jinja handler to support custom- and default-template folders for
  35. # rendering templates.
  36. app.jinja_loader = jinja2.ChoiceLoader([
  37. jinja2.FileSystemLoader(config.SITE_ROOT), # Site specific.
  38. jinja2.FileSystemLoader("rophako/www"), # Default/fall-back
  39. ])
  40. app.jinja_env.globals["csrf_token"] = rophako.utils.generate_csrf_token
  41. app.jinja_env.globals["include_page"] = rophako.utils.include
  42. # Preload the emoticon data.
  43. import rophako.model.emoticons as Emoticons
  44. Emoticons.load_theme()
  45. @app.before_request
  46. def before_request():
  47. """Called before all requests. Initialize global template variables."""
  48. # Default template vars.
  49. g.info = {
  50. "time": time.time(),
  51. "app": {
  52. "name": "Rophako",
  53. "version": __version__,
  54. "python_version": "{}.{}".format(sys.version_info.major, sys.version_info.minor),
  55. "author": "Noah Petherbridge",
  56. "photo_url": config.PHOTO_ROOT_PUBLIC,
  57. },
  58. "uri": request.path,
  59. "session": {
  60. "login": False, # Not logged in, until proven otherwise.
  61. "username": "guest",
  62. "uid": 0,
  63. "name": "Guest",
  64. "role": "user",
  65. }
  66. }
  67. # Default session vars.
  68. if not "login" in session:
  69. session.update(g.info["session"])
  70. # CSRF protection.
  71. if request.method == "POST":
  72. token = session.pop("_csrf", None)
  73. if not token or str(token) != str(request.form.get("token")):
  74. abort(403)
  75. # Refresh their login status from the DB.
  76. if session["login"]:
  77. import rophako.model.user as User
  78. if not User.exists(uid=session["uid"]):
  79. # Weird! Log them out.
  80. from rophako.modules.account import logout
  81. logout()
  82. return
  83. db = User.get_user(uid=session["uid"])
  84. session["username"] = db["username"]
  85. session["name"] = db["name"]
  86. session["role"] = db["role"]
  87. # Copy session params into g.info. The only people who should touch the
  88. # session are the login/out pages.
  89. for key in session:
  90. g.info["session"][key] = session[key]
  91. @app.context_processor
  92. def after_request():
  93. """Called just before render_template. Inject g.info into the template vars."""
  94. return g.info
  95. @app.route("/<path:path>")
  96. def catchall(path):
  97. """The catch-all path handler. If it exists in the www folders, it's sent,
  98. otherwise we give the 404 error page."""
  99. # Search for this file.
  100. for root in [config.SITE_ROOT, "rophako/www"]:
  101. abspath = os.path.abspath("{}/{}".format(root, path))
  102. if os.path.isfile(abspath):
  103. return send_file(abspath)
  104. # The exact file wasn't found, look for some extensions and index pages.
  105. suffixes = [
  106. ".html",
  107. "/index.html",
  108. ".md", # Markdown formatted pages.
  109. "/index.md",
  110. ]
  111. for suffix in suffixes:
  112. if not "." in path and os.path.isfile(abspath + suffix):
  113. # HTML, or Markdown?
  114. if suffix.endswith(".html"):
  115. return rophako.utils.template(path + suffix)
  116. else:
  117. return rophako.utils.markdown_template(abspath + suffix)
  118. return not_found("404")
  119. @app.route("/")
  120. def index():
  121. return catchall("index")
  122. @app.errorhandler(404)
  123. def not_found(error):
  124. return render_template('errors/404.html', **g.info), 404
  125. @app.errorhandler(403)
  126. def forbidden(error):
  127. return render_template('errors/403.html', **g.info), 403
  128. # Domain specific endpoints.
  129. if config.SITE_NAME == "kirsle.net":
  130. import rophako.modules.kirsle_legacy