def create_app(config_object=ProdConfig): """An application factory, as explained here: http://flask.pocoo.org/docs/patterns/appfactories/. :param config_object: The configuration object to use. """ app = Flask(__name__.split('.')[0]) app.config.from_object(config_object) register_extensions(app) register_blueprints(app) register_errorhandlers(app) register_shellcontext(app) register_commands(app) @app.before_first_request def init_rollbar(): """init rollbar module""" if app.config['ENV'] in ('production',) and app.config['ROLLBAR_API']: rollbar.init(access_token=app.config['ROLLBAR_API'], environment=app.config['ENV'], root=app.config['APP_DIR'], allow_logging_basic_config=False) got_request_exception.connect(rollbar.contrib.flask.report_exception, app) def log_email_message(message, app): app.logger.debug(message.body) if app.config['DEBUG']: email_dispatched.connect(log_email_message) return app
def init_logging(app, mail): root = logging.getLogger() root.setLevel(logging.INFO) if app.config['REMOTE_DEBUG']: sys.path.append("pycharm-debug-py3k.egg") import pydevd pydevd.settrace('127.0.0.1', port=30000, stdoutToServer=True, stderrToServer=True) if app.config['MAIL_LOG']: mail_handler = FlaskMailLogHandler(mail, '*****@*****.**', ['*****@*****.**'], 'Error from Shrek') mail_handler.setLevel(logging.ERROR) mail_handler.setFormatter(formatter) root.addHandler(mail_handler) handler = logging.handlers.RotatingFileHandler(app.config['LOGPATH'], maxBytes=1024 * 1024) handler.setLevel(int(app.config['LOGLEVEL'])) handler.setFormatter(formatter) app.logger.addHandler(handler) email_dispatched.connect(log_mail) init_security_logging()
def init_app(self, app): """Flask application initialization.""" self.init_config(app) if 'mail' not in app.extensions: Mail(app) if app.config.get('MAIL_SUPPRESS_SEND', False) or app.debug: email_dispatched.connect(self.print_email) app.extensions['invenio-mail'] = self
def record_messages(self): if not email_dispatched: raise RuntimeError("blinker must be installed") outbox = [] def _record(message, app): outbox.append(message) email_dispatched.connect(_record) try: yield outbox finally: email_dispatched.disconnect(_record)
def init_app(self, app): """Flask application initialization. The initialization will: * Set default values for the configuration variables. * Initialise the Flask mail extension. * Configure the extension to avoid the email sending in case of debug or ``MAIL_SUPPRESS_SEND`` config variable set. In this case, the email will be written in the stream configured in the extension. """ self.init_config(app) if "mail" not in app.extensions: Mail(app) if app.config.get("MAIL_SUPPRESS_SEND", False) or app.debug: email_dispatched.connect(print_email) app.extensions["invenio-mail"] = self
def init_app(self, app): """Flask application initialization. The initialization will: * Set default values for the configuration variables. * Initialise the Flask mail extension. * Configure the extension to avoid the email sending in case of debug or ``MAIL_SUPPRESS_SEND`` config variable set. In this case, the email will be written in the stream configured in the extension. """ self.init_config(app) if 'mail' not in app.extensions: Mail(app) if app.config.get('MAIL_SUPPRESS_SEND', False) or app.debug: email_dispatched.connect(print_email) app.extensions['invenio-mail'] = self
def create_app(config_name='default'): app = Flask(__name__) app.config.from_object(CONFIG[config_name]) register_blueprints(app) register_extensions(app) register_errorhandlers(app) register_shellcontext(app) register_commands(app) @app.before_request def before_request(): if current_user.is_authenticated: current_user.last_seen = maya.now().datetime() db.session.commit() g.locale = str(get_locale()) @app.after_request def set_secure_headers(response): secure_headers.framework.flask(response) return response @app.before_first_request def init_rollbar(): if app.config['ENV'] in ('production', ) and app.config['ROLLBAR_API']: app.logger.info('Initiating rollbar connection') rollbar.init(access_token=app.config['ROLLBAR_API'], environment=app.config['ENV'], root=app.config['APP_DIR'], allow_logging_basic_config=False) got_request_exception.connect( rollbar.contrib.flask.report_exception, app) app.logger.info('Rollbar initiated successfully') def log_email_message(message, app): app.logger.debug(message.body) if app.config['DEBUG']: email_dispatched.connect(log_email_message) app.redis = Redis.from_url(app.config['REDIS_URL']) app.task_queue = rq.Queue('myflaskapp-tasks', connection=app.redis) return app
from flask_mail import Mail, email_dispatched mail = Mail() def debug_email(message, app): app.logger.debug(f'Subject: {message.subject}\n' f'Body: {message.body}') email_dispatched.connect(debug_email)
else: app.config[optional] = default def log_mail_message(message, app): """If mails are disabled, their content will be outputted in the debug output""" app.logger.debug(f"A mail was supposed to be send:\n" f"[SUBJECT]:\n{message.subject}\n" f"[BODY]:\n{message.body}\n" f"[END]") if app.config["MAIL_DISABLE"]: app.config["MAIL_DEBUG"] = True app.config["MAIL_SUPPRESS_SEND"] = True email_dispatched.connect(log_mail_message) app.config["MAIL_MANAGER"] = Mail(app) # Setup Flask-SQLAlchemy app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["ADE_DB_PATH"] app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False manager.database.init_app(app) migrate = Migrate(app, manager.database) # Setup Flask-Security app.config["SECURITY_TRACKABLE"] = True app.config["SECURITY_CONFIRMABLE"] = True app.config["SECURITY_REGISTERABLE"] = True app.config["SECURITY_CHANGEABLE"] = True app.config["SECURITY_RECOVERABLE"] = True
# Development server setup ########################### # Display emails sent by flask def report_email(message, **_): """Take an outgoing message and print it to the screen.""" print(f"===== Email sent by Stuffr =====") print(f"From: {message.sender}") print(f"To: {','.join(message.recipients)}") print(f"Subject: {message.subject}") print(f"Body:\n{message.body.strip()}") email_dispatched.connect(report_email) # Debug toolbar # TODO: Figure out why this stopped working DebugToolbarExtension(app) # Show root HTML with debug toolbar @app.route('/') def debug_root(): """Serve index.html when using the debug server.""" # Using render_template so flask_debugtoolbar can do its thing return render_template('index.html') def db_created():
def create_app(dev_server=False): app = Flask(__name__) app.config.from_envvar('SETTINGS_FILE') app.jinja_options['extensions'].append('jinja2.ext.do') if install_logging: create_logging_manager(app) # Flask has now kindly installed its own log handler which we will summarily remove. app.logger.propagate = 1 app.logger.handlers = [] if not app.debug: logging.root.setLevel(logging.INFO) else: logging.root.setLevel(logging.DEBUG) from apps.metrics import request_duration, request_total # Must be run before crsf.init_app @app.before_request def before_request(): request._start_time = time.time() @app.after_request def after_request(response): try: request_duration.labels( request.endpoint, request.method).observe(time.time() - request._start_time) except AttributeError: logging.exception( "Request without _start_time - check app.before_request ordering" ) request_total.labels(request.endpoint, request.method, response.status_code).inc() return response for extension in (cdn, csrf, cache, db, mail, assets, toolbar): extension.init_app(app) def log_email(message, app): app.logger.info("Emailing %s: %r", message.recipients, message.subject) email_dispatched.connect(log_email) cors_origins = ['https://map.emfcamp.org', 'https://wiki.emfcamp.org'] if app.config.get('DEBUG'): cors_origins = ['http://localhost:8080', 'https://maputnik.github.io'] CORS(app, resources={r"/api/*": { "origins": cors_origins }}, supports_credentials=True) migrate.init_app(app, db) login_manager.setup_app(app, add_context_processor=True) app.login_manager.login_view = 'users.login' from models.user import User, load_anonymous_user from models import site_state, feature_flag @login_manager.user_loader def load_user(userid): user = User.query.filter_by(id=userid).first() if user: set_user_id(user.email) return user login_manager.anonymous_user = load_anonymous_user if app.config.get('TICKETS_SITE'): global gocardless_client gocardless_client = gocardless_pro.Client( access_token=app.config['GOCARDLESS_ACCESS_TOKEN'], environment=app.config['GOCARDLESS_ENVIRONMENT']) stripe.api_key = app.config['STRIPE_SECRET_KEY'] @app.before_request def load_per_request_state(): site_state.get_states() feature_flag.get_db_flags() if app.config.get('NO_INDEX'): # Prevent staging site from being displayed on Google @app.after_request def send_noindex_header(response): response.headers['X-Robots-Tag'] = 'noindex, nofollow' return response @app.before_request def simple_cache_warning(): if not dev_server and app.config.get('CACHE_TYPE', 'null') == 'simple': logging.warn( 'Per-process cache being used outside dev server - refreshing will not work' ) @app.after_request def send_security_headers(response): use_hsts = app.config.get('HSTS', False) if use_hsts: max_age = app.config.get('HSTS_MAX_AGE', 3600 * 24 * 7 * 4) response.headers[ 'Strict-Transport-Security'] = 'max-age=%s' % max_age response.headers['X-Frame-Options'] = 'deny' response.headers['X-Content-Type-Options'] = 'nosniff' return response @app.errorhandler(404) def handle_404(e): return render_template('errors/404.html'), 404 @app.errorhandler(500) def handle_500(e): return render_template('errors/500.html'), 500 @app.shell_context_processor def shell_imports(): ctx = {} # Import models and constants import models for attr in dir(models): if attr[0].isupper(): ctx[attr] = getattr(models, attr) # And just for convenience ctx['db'] = db return ctx from apps.common import load_utility_functions load_utility_functions(app) from apps.base import base from apps.metrics import metrics from apps.users import users from apps.tickets import tickets from apps.payments import payments from apps.cfp import cfp from apps.cfp_review import cfp_review from apps.schedule import schedule from apps.arrivals import arrivals from apps.api import api_bp app.register_blueprint(base) app.register_blueprint(users) app.register_blueprint(metrics) app.register_blueprint(tickets) app.register_blueprint(payments) app.register_blueprint(cfp) app.register_blueprint(cfp_review, url_prefix='/cfp-review') app.register_blueprint(schedule) app.register_blueprint(arrivals, url_prefix='/arrivals') app.register_blueprint(api_bp, url_prefix='/api') if app.config.get('VOLUNTEERS'): from apps.volunteer import volunteer app.register_blueprint(volunteer, url_prefix='/volunteer') from flask_admin import Admin from apps.volunteer.flask_admin_base import VolunteerAdminIndexView global volunteer_admin volunteer_admin = Admin( url='/volunteer/admin', name='EMF Volunteers', template_mode='bootstrap3', index_view=VolunteerAdminIndexView(url='/volunteer/admin'), base_template='volunteer/admin/flask-admin-base.html') volunteer_admin.endpoint_prefix = 'volunteer_admin' volunteer_admin.init_app(app) import apps.volunteer.admin # noqa: F401 from apps.admin import admin app.register_blueprint(admin, url_prefix='/admin') return app
from flask import current_app from flask_mail import email_dispatched from flask_login import user_logged_in, user_logged_out from app.logger import log_user_operation, log_email_operation def _after_sending_email_hook(message, app): log_email_operation(message, 'sent') email_dispatched.connect(_after_sending_email_hook) # @user_logged_in.connect_via(current_app) def _after_user_logged_in_hook(sender, user, **extra): log_user_operation(user, 'logged in') user_logged_in.connect(_after_user_logged_in_hook) # @user_logged_out.connect_via(current_app) def _after_user_logged_out_hook(sender, user, **extra): log_user_operation(user, 'logged out') user_logged_out.connect(_after_user_logged_out_hook)
def fix_shared_state(): if os.getpid() != ppid: db.engine.dispose() random.seed() import prometheus_client.multiprocess @app.after_request def prometheus_cleanup(response): # this keeps livesum and liveall accurate # other metrics will hang around until restart prometheus_client.multiprocess.mark_process_dead(os.getpid()) return response if app.config.get('DEBUG') or app.config.get('MAIL_SUPPRESS_SEND'): email_dispatched.connect(logger.mail_logging) if app.config.get('FIX_URL_SCHEME'): # The Flask debug server doesn't process _FORWARDED_ headers, # so there's no other way to set the wsgi.url_scheme. # Consider using an actual WSGI host (perhaps with ProxyFix) instead. @app.before_request def fix_url_scheme(): if request.environ.get('HTTP_X_FORWARDED_PROTO') == 'https': request.environ['wsgi.url_scheme'] = 'https' _request_ctx_stack.top.url_adapter.url_scheme = 'https' if os.path.exists('.inside-vagrant'): # Make it easier to access from host machine default_host = '0.0.0.0'
def create_app(dev_server=False): app = Flask(__name__) app.config.from_envvar('SETTINGS_FILE') app.jinja_options['extensions'].append('jinja2.ext.do') if install_logging: create_logging_manager(app) # Flask has now kindly installed its own log handler which we will summarily remove. app.logger.propagate = 1 app.logger.handlers = [] if not app.debug: logging.root.setLevel(logging.INFO) else: logging.root.setLevel(logging.DEBUG) from apps.metrics import request_duration, request_total # Must be run before crsf.init_app @app.before_request def before_request(): request._start_time = time.time() @app.after_request def after_request(response): try: request_duration.labels(request.endpoint, request.method).observe( time.time() - request._start_time) except AttributeError: logging.exception("Request without _start_time - check app.before_request ordering") request_total.labels(request.endpoint, request.method, response.status_code).inc() return response for extension in (cdn, csrf, cache, db, mail, assets, toolbar): extension.init_app(app) def log_email(message, app): app.logger.info("Emailing %s: %r", message.recipients, message.subject) email_dispatched.connect(log_email) cors_origins = ['https://map.emfcamp.org', 'https://wiki.emfcamp.org'] if app.config.get('DEBUG'): cors_origins = ['http://localhost:8080', 'https://maputnik.github.io'] CORS(app, resources={r"/api/*": {"origins": cors_origins}}, supports_credentials=True) migrate.init_app(app, db) login_manager.setup_app(app, add_context_processor=True) app.login_manager.login_view = 'users.login' from models.user import User, load_anonymous_user from models import site_state, feature_flag @login_manager.user_loader def load_user(userid): user = User.query.filter_by(id=userid).first() if user: set_user_id(user.email) return user login_manager.anonymous_user = load_anonymous_user if app.config.get('TICKETS_SITE'): global gocardless_client gocardless_client = gocardless_pro.Client(access_token=app.config['GOCARDLESS_ACCESS_TOKEN'], environment=app.config['GOCARDLESS_ENVIRONMENT']) stripe.api_key = app.config['STRIPE_SECRET_KEY'] @app.before_request def load_per_request_state(): site_state.get_states() feature_flag.get_db_flags() if app.config.get('NO_INDEX'): # Prevent staging site from being displayed on Google @app.after_request def send_noindex_header(response): response.headers['X-Robots-Tag'] = 'noindex, nofollow' return response @app.before_request def simple_cache_warning(): if not dev_server and app.config.get('CACHE_TYPE', 'null') == 'simple': logging.warn('Per-process cache being used outside dev server - refreshing will not work') @app.after_request def send_security_headers(response): use_hsts = app.config.get('HSTS', False) if use_hsts: max_age = app.config.get('HSTS_MAX_AGE', 3600 * 24 * 7 * 4) response.headers['Strict-Transport-Security'] = 'max-age=%s' % max_age response.headers['X-Frame-Options'] = 'deny' response.headers['X-Content-Type-Options'] = 'nosniff' return response @app.errorhandler(404) def handle_404(e): return render_template('errors/404.html'), 404 @app.errorhandler(500) def handle_500(e): return render_template('errors/500.html'), 500 @app.shell_context_processor def shell_imports(): ctx = {} # Import models and constants import models for attr in dir(models): if attr[0].isupper(): ctx[attr] = getattr(models, attr) # And just for convenience ctx['db'] = db return ctx from apps.common import load_utility_functions load_utility_functions(app) from apps.base import base from apps.metrics import metrics from apps.users import users from apps.tickets import tickets from apps.payments import payments from apps.cfp import cfp from apps.cfp_review import cfp_review from apps.schedule import schedule from apps.arrivals import arrivals from apps.api import api_bp app.register_blueprint(base) app.register_blueprint(users) app.register_blueprint(metrics) app.register_blueprint(tickets) app.register_blueprint(payments) app.register_blueprint(cfp) app.register_blueprint(cfp_review, url_prefix='/cfp-review') app.register_blueprint(schedule) app.register_blueprint(arrivals, url_prefix='/arrivals') app.register_blueprint(api_bp, url_prefix='/api') if app.config.get('VOLUNTEERS'): from apps.volunteer import volunteer app.register_blueprint(volunteer, url_prefix='/volunteer') from flask_admin import Admin from apps.volunteer.flask_admin_base import VolunteerAdminIndexView global volunteer_admin volunteer_admin = Admin(url='/volunteer/admin', name='EMF Volunteers', template_mode='bootstrap3', index_view=VolunteerAdminIndexView(url='/volunteer/admin'), base_template='volunteer/admin/flask-admin-base.html') volunteer_admin.endpoint_prefix = 'volunteer_admin' volunteer_admin.init_app(app) import apps.volunteer.admin # noqa: F401 from apps.admin import admin app.register_blueprint(admin, url_prefix='/admin') from apps.notification import notify app.register_blueprint(notify, url_prefix='/notify') return app
from flask_mail import Message, email_dispatched from ..audit import auditable_event from ..database import db from ..extensions import mail from .user import User def log_message(message, app): """Configured to handle signals on email_dispatched - log the event""" app.logger.info("Message sent; To: {0} Subj: {1}".format( message.recipients, message.subject)) email_dispatched.connect(log_message) EMAIL_HEADER = ( "<!DOCTYPE html><html>" "<head><title>TrueNTH email</title><style>" "body {" " font-size: 16px;" "} " "table, th, td {" " border: 1px solid #ddd;" "} " "table { " " border-collapse: collapse;" " border-spacing: 0;" " display: table;" "} "
pmail_kwargs = { 'cssutils_logging_handler': cssutils_handler, 'cssutils_logging_level': logging.FATAL, 'cache_css_parsing': True, } pmail = None log = logging.getLogger(__name__) def status(message, app): message.status = 'sent' email_dispatched.connect(status) def _format_datetime(dt, verbose=False): """ REF: https://stackoverflow.com/a/5891598 """ def _suffix(d): return 'th' if 11 <= d <= 13 else { 1: 'st', 2: 'nd', 3: 'rd' }.get(d % 10, 'th') if verbose: time_fmtstr = '%B {S}, %Y at %I:%M %p'
def create_app(dev_server=False, config_override=None): app = Flask(__name__) app.config.from_envvar("SETTINGS_FILE") if config_override: app.config.from_mapping(config_override) app.jinja_options["extensions"].append("jinja2.ext.do") if install_logging: create_logging_manager(app) # Flask has now kindly installed its own log handler which we will summarily remove. app.logger.propagate = 1 app.logger.handlers = [] if not app.debug: logging.root.setLevel(logging.INFO) else: logging.root.setLevel(logging.DEBUG) from apps.metrics import request_duration, request_total # Must be run before crsf.init_app @app.before_request def before_request(): request._start_time = time.time() @app.after_request def after_request(response): try: request_duration.labels( request.endpoint, request.method).observe(time.time() - request._start_time) except AttributeError: logging.exception( "Request without _start_time - check app.before_request ordering" ) request_total.labels(request.endpoint, request.method, response.status_code).inc() return response for extension in (csrf, cache, db, mail, static_digest, toolbar): extension.init_app(app) def log_email(message, app): app.logger.info("Emailing %s: %r", message.recipients, message.subject) email_dispatched.connect(log_email) cors_origins = ["https://map.emfcamp.org", "https://wiki.emfcamp.org"] if app.config.get("DEBUG"): cors_origins = ["http://localhost:8080", "https://maputnik.github.io"] CORS(app, resources={r"/api/*": { "origins": cors_origins }}, supports_credentials=True) migrate.init_app(app, db) login_manager.init_app(app, add_context_processor=True) app.login_manager.login_view = "users.login" from models.user import User, load_anonymous_user from models import site_state, feature_flag @login_manager.user_loader def load_user(userid): user = User.query.filter_by(id=userid).first() if user: set_user_id(user.email) return user login_manager.anonymous_user = load_anonymous_user global gocardless_client gocardless_client = gocardless_pro.Client( access_token=app.config["GOCARDLESS_ACCESS_TOKEN"], environment=app.config["GOCARDLESS_ENVIRONMENT"], ) stripe.api_key = app.config["STRIPE_SECRET_KEY"] pytransferwise.environment = app.config["TRANSFERWISE_ENVIRONMENT"] pytransferwise.api_key = app.config["TRANSFERWISE_API_TOKEN"] @app.before_request def load_per_request_state(): site_state.get_states() feature_flag.get_db_flags() if app.config.get("NO_INDEX"): # Prevent staging site from being displayed on Google @app.after_request def send_noindex_header(response): response.headers["X-Robots-Tag"] = "noindex, nofollow" return response @app.before_request def simple_cache_warning(): if not dev_server and app.config.get("CACHE_TYPE", "null") == "simple": logging.warning( "Per-process cache being used outside dev server - refreshing will not work" ) @app.context_processor def add_csp_nonce(): g.csp_nonce = secrets.token_urlsafe(16) return {"csp_nonce": g.csp_nonce} @app.after_request def send_security_headers(response): use_hsts = app.config.get("HSTS", False) if use_hsts: max_age = app.config.get("HSTS_MAX_AGE", 3600 * 24 * 30 * 6) response.headers[ "Strict-Transport-Security"] = "max-age=%s" % max_age response.headers["X-Frame-Options"] = "deny" response.headers["X-Content-Type-Options"] = "nosniff" response.headers["X-XSS-Protection"] = "1; mode=block" response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin" csp = { "script-src": ["'self'", "https://js.stripe.com"], "style-src": ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"], # Note: the below is more strict as it only allows inline styles in style= # attributes, however it's unsupported by Safari at this time... # "style-src-attr": ["'unsafe-inline'"], "font-src": ["'self'", "https://fonts.gstatic.com"], "frame-src": [ "https://js.stripe.com/", "https://media.ccc.de", "https://www.youtube.com", "https://archive.org", ], } # Edit record hash to support the modal dialogues in flask-admin csp["script-src"].append( "'sha256-Jxve8bBSodQplIZw4Y1walBJ0hFTx8sZ5xr+Pjr/78Y='") # View record hash to support the modal dialogues in flask-admin csp["script-src"].append( "'sha256-XOlW2U5UiDeV2S/HgKqbp++Fo1I5uiUT2thFRUeFW/g='") if app.config.get("DEBUG_TB_ENABLED"): # This hash is for the flask debug toolbar. It may break once they upgrade it. csp["script-src"].append( "'sha256-zWl5GfUhAzM8qz2mveQVnvu/VPnCS6QL7Niu6uLmoWU='") if "csp_nonce" in g: csp["script-src"].append(f"'nonce-{g.csp_nonce}'") value = "; ".join(k + " " + " ".join(v) for k, v in csp.items()) if app.config.get("DEBUG"): response.headers["Content-Security-Policy"] = value else: response.headers["Content-Security-Policy-Report-Only"] = ( value + "; report-uri https://emfcamp.report-uri.com/r/d/csp/reportOnly" ) response.headers[ "Report-To"] = '{"group":"default","max_age":31536000,"endpoints":[{"url":"https://emfcamp.report-uri.com/a/d/g"}],"include_subdomains":false}' # Disable Network Error Logging. # This doesn't seem to be very useful and it's using up our report-uri quota. response.headers["NEL"] = '{"max_age":0}' return response if not app.debug: @app.errorhandler(Exception) def handle_exception(e): """ Generic exception handler to catch and log unhandled exceptions in production. """ if isinstance(e, HTTPException): # HTTPException is used to implement flask's HTTP errors so pass it through. return e app.logger.exception("Unhandled exception in request: %s", request) return render_template("errors/500.html"), 500 @app.errorhandler(404) def handle_404(e): return render_template("errors/404.html"), 404 @app.errorhandler(500) def handle_500(e): return render_template("errors/500.html"), 500 @app.shell_context_processor def shell_imports(): ctx = {} # Import models and constants import models for attr in dir(models): if attr[0].isupper(): ctx[attr] = getattr(models, attr) # And just for convenience ctx["db"] = db return ctx from apps.common import load_utility_functions load_utility_functions(app) from apps.base import base from apps.metrics import metrics from apps.users import users from apps.tickets import tickets from apps.payments import payments from apps.cfp import cfp from apps.cfp_review import cfp_review from apps.schedule import schedule from apps.arrivals import arrivals from apps.api import api_bp from apps.villages import villages app.register_blueprint(base) app.register_blueprint(users) app.register_blueprint(metrics) app.register_blueprint(tickets) app.register_blueprint(payments) app.register_blueprint(cfp) app.register_blueprint(cfp_review, url_prefix="/cfp-review") app.register_blueprint(schedule) app.register_blueprint(arrivals, url_prefix="/arrivals") app.register_blueprint(api_bp, url_prefix="/api") app.register_blueprint(villages, url_prefix="/villages") if app.config.get("VOLUNTEERS"): from apps.volunteer import volunteer app.register_blueprint(volunteer, url_prefix="/volunteer") from flask_admin import Admin from apps.volunteer.flask_admin_base import VolunteerAdminIndexView global volunteer_admin volunteer_admin = Admin( url="/volunteer/admin", name="EMF Volunteers", template_mode="bootstrap3", index_view=VolunteerAdminIndexView(url="/volunteer/admin"), base_template="volunteer/admin/flask-admin-base.html", ) volunteer_admin.endpoint_prefix = "volunteer_admin" volunteer_admin.init_app(app) import apps.volunteer.admin # noqa: F401 from apps.admin import admin app.register_blueprint(admin, url_prefix="/admin") from apps.notification import notify app.register_blueprint(notify, url_prefix="/notify") return app
# coding: utf-8 from flask import render_template, request from flask_debugtoolbar import module from flask_debugtoolbar.panels import DebugPanel from flask_mail import email_dispatched, Mail mail = Mail() def log_email(email, app): if app.debug: EmailDebugPanel.emails.append(email) email_dispatched.connect(log_email) class EmailDebugPanel(DebugPanel): emails = [] name = "Emails" def __init__(self, jinja_env, context={}): DebugPanel.__init__(self, jinja_env, context=context) self.is_active = True @property def has_content(self): return bool(self.emails) def title(self):
def register_users_blueprint_and_signals(app): """Registers blueprint to app and connects signals""" app.register_blueprint(users_blueprint) user_confirmed.connect(when_user_confirmed) email_dispatched.connect(log_email_message) update_user_rss.connect(when_update_user_rss)
def create_app(dev_server=False): app = Flask(__name__) app.config.from_envvar("SETTINGS_FILE") app.jinja_options["extensions"].append("jinja2.ext.do") if install_logging: create_logging_manager(app) # Flask has now kindly installed its own log handler which we will summarily remove. app.logger.propagate = 1 app.logger.handlers = [] if not app.debug: logging.root.setLevel(logging.INFO) else: logging.root.setLevel(logging.DEBUG) from apps.metrics import request_duration, request_total # Must be run before crsf.init_app @app.before_request def before_request(): request._start_time = time.time() @app.after_request def after_request(response): try: request_duration.labels( request.endpoint, request.method).observe(time.time() - request._start_time) except AttributeError: logging.exception( "Request without _start_time - check app.before_request ordering" ) request_total.labels(request.endpoint, request.method, response.status_code).inc() return response for extension in (csrf, cache, db, mail, static_digest, toolbar): extension.init_app(app) def log_email(message, app): app.logger.info("Emailing %s: %r", message.recipients, message.subject) email_dispatched.connect(log_email) cors_origins = ["https://map.emfcamp.org", "https://wiki.emfcamp.org"] if app.config.get("DEBUG"): cors_origins = ["http://localhost:8080", "https://maputnik.github.io"] CORS(app, resources={r"/api/*": { "origins": cors_origins }}, supports_credentials=True) migrate.init_app(app, db) login_manager.init_app(app, add_context_processor=True) app.login_manager.login_view = "users.login" from models.user import User, load_anonymous_user from models import site_state, feature_flag @login_manager.user_loader def load_user(userid): user = User.query.filter_by(id=userid).first() if user: set_user_id(user.email) return user login_manager.anonymous_user = load_anonymous_user global gocardless_client gocardless_client = gocardless_pro.Client( access_token=app.config["GOCARDLESS_ACCESS_TOKEN"], environment=app.config["GOCARDLESS_ENVIRONMENT"], ) stripe.api_key = app.config["STRIPE_SECRET_KEY"] @app.before_request def load_per_request_state(): site_state.get_states() feature_flag.get_db_flags() if app.config.get("NO_INDEX"): # Prevent staging site from being displayed on Google @app.after_request def send_noindex_header(response): response.headers["X-Robots-Tag"] = "noindex, nofollow" return response @app.before_request def simple_cache_warning(): if not dev_server and app.config.get("CACHE_TYPE", "null") == "simple": logging.warn( "Per-process cache being used outside dev server - refreshing will not work" ) @app.after_request def send_security_headers(response): use_hsts = app.config.get("HSTS", False) if use_hsts: max_age = app.config.get("HSTS_MAX_AGE", 3600 * 24 * 30 * 6) response.headers[ "Strict-Transport-Security"] = "max-age=%s" % max_age response.headers["X-Frame-Options"] = "deny" response.headers["X-Content-Type-Options"] = "nosniff" return response if not app.debug: @app.errorhandler(Exception) def handle_exception(e): """ Generic exception handler to catch and log unhandled exceptions in production. """ if isinstance(e, HTTPException): # HTTPException is used to implement flask's HTTP errors so pass it through. return e app.logger.exception("Unhandled exception in request: %s", request) return render_template("errors/500.html"), 500 @app.errorhandler(404) def handle_404(e): return render_template("errors/404.html"), 404 @app.errorhandler(500) def handle_500(e): return render_template("errors/500.html"), 500 @app.shell_context_processor def shell_imports(): ctx = {} # Import models and constants import models for attr in dir(models): if attr[0].isupper(): ctx[attr] = getattr(models, attr) # And just for convenience ctx["db"] = db return ctx from apps.common import load_utility_functions load_utility_functions(app) from apps.base import base from apps.metrics import metrics from apps.users import users from apps.tickets import tickets from apps.payments import payments from apps.cfp import cfp from apps.cfp_review import cfp_review from apps.schedule import schedule from apps.arrivals import arrivals from apps.api import api_bp app.register_blueprint(base) app.register_blueprint(users) app.register_blueprint(metrics) app.register_blueprint(tickets) app.register_blueprint(payments) app.register_blueprint(cfp) app.register_blueprint(cfp_review, url_prefix="/cfp-review") app.register_blueprint(schedule) app.register_blueprint(arrivals, url_prefix="/arrivals") app.register_blueprint(api_bp, url_prefix="/api") if app.config.get("VOLUNTEERS"): from apps.volunteer import volunteer app.register_blueprint(volunteer, url_prefix="/volunteer") from flask_admin import Admin from apps.volunteer.flask_admin_base import VolunteerAdminIndexView global volunteer_admin volunteer_admin = Admin( url="/volunteer/admin", name="EMF Volunteers", template_mode="bootstrap3", index_view=VolunteerAdminIndexView(url="/volunteer/admin"), base_template="volunteer/admin/flask-admin-base.html", ) volunteer_admin.endpoint_prefix = "volunteer_admin" volunteer_admin.init_app(app) import apps.volunteer.admin # noqa: F401 from apps.admin import admin app.register_blueprint(admin, url_prefix="/admin") from apps.notification import notify app.register_blueprint(notify, url_prefix="/notify") return app