mirror of
https://github.com/spiral-project/ihatemoney.git
synced 2025-04-29 17:52:37 +02:00
157 lines
4.9 KiB
Python
157 lines
4.9 KiB
Python
import os
|
|
import os.path
|
|
import warnings
|
|
|
|
from flask import Flask, g, request, session
|
|
from flask_babel import Babel
|
|
from flask_mail import Mail
|
|
from flask_migrate import Migrate, upgrade, stamp
|
|
from raven.contrib.flask import Sentry
|
|
from werkzeug.contrib.fixers import ProxyFix
|
|
|
|
from ihatemoney.api import api
|
|
from ihatemoney.models import db
|
|
from ihatemoney.utils import PrefixedWSGI, minimal_round
|
|
from ihatemoney.web import main as web_interface
|
|
|
|
from ihatemoney import default_settings
|
|
|
|
|
|
def setup_database(app):
|
|
"""Prepare the database. Create tables, run migrations etc."""
|
|
|
|
def _pre_alembic_db():
|
|
""" Checks if we are migrating from a pre-alembic ihatemoney
|
|
"""
|
|
con = db.engine.connect()
|
|
tables_exist = db.engine.dialect.has_table(con, 'project')
|
|
alembic_setup = db.engine.dialect.has_table(con, 'alembic_version')
|
|
return tables_exist and not alembic_setup
|
|
|
|
sqlalchemy_url = app.config.get('SQLALCHEMY_DATABASE_URI')
|
|
if sqlalchemy_url.startswith('sqlite:////tmp'):
|
|
warnings.warn(
|
|
'The database is currently stored in /tmp and might be lost at '
|
|
'next reboot.'
|
|
)
|
|
|
|
db.init_app(app)
|
|
db.app = app
|
|
|
|
Migrate(app, db)
|
|
migrations_path = os.path.join(app.root_path, 'migrations')
|
|
|
|
if _pre_alembic_db():
|
|
with app.app_context():
|
|
# fake the first migration
|
|
stamp(migrations_path, revision='b9a10d5d63ce')
|
|
|
|
# auto-execute migrations on runtime
|
|
with app.app_context():
|
|
upgrade(migrations_path)
|
|
|
|
|
|
def load_configuration(app, configuration=None):
|
|
""" Find the right configuration file for the application and load it.
|
|
|
|
By order of preference:
|
|
- Use the IHATEMONEY_SETTINGS_FILE_PATH env var if defined ;
|
|
- If not, use /etc/ihatemoney/ihatemoney.cfg ;
|
|
- Otherwise, load the default settings.
|
|
"""
|
|
|
|
env_var_config = os.environ.get('IHATEMONEY_SETTINGS_FILE_PATH')
|
|
app.config.from_object('ihatemoney.default_settings')
|
|
if configuration:
|
|
app.config.from_object(configuration)
|
|
elif env_var_config:
|
|
app.config.from_pyfile(env_var_config)
|
|
else:
|
|
app.config.from_pyfile('ihatemoney.cfg', silent=True)
|
|
|
|
|
|
def validate_configuration(app):
|
|
|
|
if app.config['SECRET_KEY'] == default_settings.SECRET_KEY:
|
|
warnings.warn(
|
|
"Running a server without changing the SECRET_KEY can lead to"
|
|
+ " user impersonation. Please update your configuration file.",
|
|
UserWarning
|
|
)
|
|
# Deprecations
|
|
if 'DEFAULT_MAIL_SENDER' in app.config:
|
|
# Since flask-mail 0.8
|
|
warnings.warn(
|
|
"DEFAULT_MAIL_SENDER is deprecated in favor of MAIL_DEFAULT_SENDER"
|
|
+ " and will be removed in further version",
|
|
UserWarning
|
|
)
|
|
if 'MAIL_DEFAULT_SENDER' not in app.config:
|
|
app.config['MAIL_DEFAULT_SENDER'] = default_settings.DEFAULT_MAIL_SENDER
|
|
|
|
if "pbkdf2:sha256:" not in app.config['ADMIN_PASSWORD'] and app.config['ADMIN_PASSWORD']:
|
|
# Since 2.0
|
|
warnings.warn(
|
|
"The way Ihatemoney stores your ADMIN_PASSWORD has changed. You are using an unhashed"
|
|
+ " ADMIN_PASSWORD, which is not supported anymore and won't let you access your admin"
|
|
+ " endpoints. Please use the command 'ihatemoney generate_password_hash'"
|
|
+ " to generate a proper password HASH and copy the output to the value of"
|
|
+ " ADMIN_PASSWORD in your settings file.",
|
|
UserWarning
|
|
)
|
|
|
|
|
|
def create_app(configuration=None, instance_path='/etc/ihatemoney',
|
|
instance_relative_config=True):
|
|
app = Flask(
|
|
__name__,
|
|
instance_path=instance_path,
|
|
instance_relative_config=instance_relative_config)
|
|
|
|
# If a configuration object is passed, use it. Otherwise try to find one.
|
|
load_configuration(app, configuration)
|
|
app.wsgi_app = PrefixedWSGI(app)
|
|
|
|
# Get client's real IP
|
|
# Note(0livd): When running in a non-proxy setup, is vulnerable to requests
|
|
# with a forged X-FORWARDED-FOR header
|
|
app.wsgi_app = ProxyFix(app.wsgi_app)
|
|
|
|
validate_configuration(app)
|
|
app.register_blueprint(web_interface)
|
|
app.register_blueprint(api)
|
|
|
|
# Configure the application
|
|
setup_database(app)
|
|
|
|
mail = Mail()
|
|
mail.init_app(app)
|
|
app.mail = mail
|
|
|
|
# Error reporting
|
|
Sentry(app)
|
|
|
|
# Jinja filters
|
|
app.jinja_env.filters['minimal_round'] = minimal_round
|
|
|
|
# Translations
|
|
babel = Babel(app)
|
|
|
|
@babel.localeselector
|
|
def get_locale():
|
|
# get the lang from the session if defined, fallback on the browser "accept
|
|
# languages" header.
|
|
lang = session.get('lang', request.accept_languages.best_match(['fr', 'en']))
|
|
setattr(g, 'lang', lang)
|
|
return lang
|
|
|
|
return app
|
|
|
|
|
|
def main():
|
|
app = create_app()
|
|
app.run(host="0.0.0.0", debug=True)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|