Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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()
Ejemplo n.º 3
0
 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
Ejemplo n.º 4
0
 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
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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)
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0

# 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():
Ejemplo n.º 13
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')

    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)
Ejemplo n.º 15
0
    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'
Ejemplo n.º 16
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
Ejemplo n.º 17
0
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;"
    "} "
Ejemplo n.º 18
0
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'
Ejemplo n.º 19
0
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
Ejemplo n.º 20
0
# 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):
Ejemplo n.º 21
0
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)
Ejemplo n.º 22
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 (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