1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""

from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_wtf.csrf import CSRFProtect
from flask_mail import Mail, email_dispatched
from flask_babelex import Babel, Domain
from flask_security import Security

db = SQLAlchemy()
migrate = Migrate()
csrf = CSRFProtect()
mail = Mail()
babel = Babel(default_domain=Domain('translations', domain='messages'))
# https://github.com/lingthio/Flask-User/issues/195#issuecomment-352274132
babel.translation_directories = 'translations'
babel.domain = 'webapp'
security = Security()


# When testing without proper mail server set up, set MAIL_SUPPRESS_SEND = True
# config property to enable mail logging.
@email_dispatched.connect
def log_message(message, app):
    if app.config.get('MAIL_SUPPRESS_SEND'):
        app.logger.info('%s\n%s', message.subject, message.body)
예제 #2
0
db.init_app(app)
mig = Migrate(app=app,
              db=db,
              directory=app.config.get('MIGRATE_DIRECTORY', 'data/migrations'))
Bootstrap(app)

security.init_app(app,
                  data_store,
                  login_form=LoginUserForm,
                  register_form=RegisterUserForm)
admin.admin.init_app(app)

domain = Domain(app.config.get("BABEL_TRANSLATIONS")[0], "messages")
babel = Babel(app, default_domain=domain)
babel.domain = "messages"
babel.translation_directories = app.config.get("BABEL_TRANSLATIONS")


@babel.localeselector
def get_locale():
    if current_user.is_authenticated:
        return current_user.language or 'hu'
    return request.accept_languages.best_match(app.config.get('LANGUAGES'))


@babel.timezoneselector
def get_timezone():
    if current_user.is_authenticated:
        return

예제 #3
0
def create_app(config, register_blueprints=True):
    app = Flask(__name__)
    app.config.from_object(config)

    convention = {
        "ix": 'ix_%(column_0_label)s',
        "uq": "uq_%(table_name)s_%(column_0_name)s",
        "ck": "ck_%(table_name)s_%(constraint_name)s",
        "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
        "pk": "pk_%(table_name)s"
    }
    MetaData(naming_convention=convention)
    db.init_app(app)

    #app.config['PROFILE'] = True
    #app.wsgi_app = ProfilerMiddleware(app.wsgi_app, restrictions=[30])

    # This needs to be after db is instantiated for migrate to discover
    from portal.user.models import Role, User
    from portal.account.models import Account
    from portal.vps.models import Vps
    from portal.vendor.models import Vendor
    from portal.transfer.models import Transfer
    from portal.bank_account.models import BankAccount
    from portal.permission.models import Permission
    Migrate(app, db)

    db_adapter = SQLAlchemyAdapter(db, User)
    UserManager(db_adapter, app)

    Compress(app)

    #DebugToolbarExtension(app)

    cache.init_app(app, config={'CACHE_TYPE': 'simple'})

    babel = Babel(app)
    # Monkeypatching Flask-babel
    babel.domain = 'flask_user'
    babel.translation_directories = 'translations'
    # All the translation should be done using Flask_Babelex's lazy_gettext as
    # opposed to flask_admin.babel's. The latter is referencing the domain
    # flask_admin.

    @babel.localeselector
    def get_locale():
        if request.args.get('lang'):
            session['lang'] = request.args.get('lang')
        return session.get('lang', 'en')

    class JSONEncoder(BaseEncoder):
        """so/questions/26124581/flask-json-serializable-error-because-of-flask-babel
        """
        def default(self, o):
            if isinstance(o, _LazyString):
                return text_type(o)
            return BaseEncoder.default(self, o)

    app.json_encoder = JSONEncoder

    @app.route('/')
    def default_page():
        if is_authenticated():
            return redirect(url_for('user.member_page'))
        return redirect(url_for('user.home_page'))

    def get_account_view_endpoint(suffix=None):
        """Returns 'ROLE_account.X' based on current_user
        """
        if not is_authenticated():
            raise Exception("Attempt to call get_account_view_endpoint without authentication")

        assert len(current_user.roles) == 1, 'User has more than 1 role!'
        if suffix:
            return '%s_account.%s' % (current_user.roles[0].name, suffix)
        return '%s_account' % current_user.roles[0].name

    class RegexConverter(BaseConverter):
        def __init__(self, url_map, *items):
            super(RegexConverter, self).__init__(url_map)
            self.regex = items[0]

    app.url_map.converters['regex'] = RegexConverter

    @app.context_processor
    def inject_admin_views():
        return dict(is_heroku=issubclass(config, HerokuConfig),     # isinstance doesn't work
                    admin_view=root.index_view, h=admin_helpers, get_url=url_for,
                    get_account_view_endpoint=get_account_view_endpoint)

    @app.template_filter()
    def format_currency(value):
        try:
            return "{:,.2f}".format(value)
        except ValueError:
            return value

    @app.template_filter()
    def to_hktz(value):
        if value:
            return value.astimezone(pytz.timezone('Asia/Hong_Kong'))

    @app.template_filter()
    def format_datetime(value):
        if value:
            return value.strftime('%m/%d %H:%M')

    if register_blueprints:     # prevent cyclical imports
        from portal.user.views import user_blueprint
        from portal.access.views import access_blueprint
        from portal.api.eve import eve_blueprint
        from portal.api.prometheus import prometheus_blueprint

        app.register_blueprint(user_blueprint, url_prefix='/user')
        app.register_blueprint(access_blueprint, url_prefix='/access')
        app.register_blueprint(eve_blueprint, url_prefix='/eve')
        app.register_blueprint(prometheus_blueprint, url_prefix='/prometheus')

        root = Admin(app, name='Portal', url='/', template_mode='bootstrap3')

        root.add_menu_item(RoleBasedMenuLink(name=lazy_gettext('Budget'),
                                             endpoint='user.budget',
                                             roles=[RolesEnum.CLIENT.value]))
        root.add_menu_item(RoleBasedMenuLink(name=lazy_gettext('Appointments'),
                                             endpoint='user.appointments',
                                             roles=[RolesEnum.CLIENT.value]))

        from portal.admin.views import UserModelView, RoleModelView
        root.add_view(UserModelView(User, db.session,
                                    category=lazy_gettext('User'), endpoint='admin_user'))
        root.add_view(RoleModelView(Role, db.session,
                                    category=lazy_gettext('User'), endpoint='admin_role'))

        from portal.account.views import account_blueprint, AdminAccountModelView, \
            TechnicianAccountModelView, SupportAccountModelView, ClientAccountModelView
        app.register_blueprint(account_blueprint, url_prefix='/account')

        ac = lazy_gettext('Account')

        root.add_view(AdminAccountModelView(
            Account, db.session, category=ac,
            name=lazy_gettext('Account (Admin)'), endpoint='admin_account'))
        root.add_view(SupportAccountModelView(
            Account, db.session, category=ac,
            name=lazy_gettext('Account (Support)'), endpoint='support_account'))
        root.add_view(TechnicianAccountModelView(
            Account, db.session, category=ac,
            name=lazy_gettext('Account (Technician)'), endpoint='technician_account'))
        root.add_view(ClientAccountModelView(
            Account, db.session, category=ac,
            name=lazy_gettext('Account (Client)'), endpoint='client_account'))

        root.add_link(UsernameBasedMenuLink(
            name=lazy_gettext('Batch Add'), category=ac,
            url='/account/handson_batch', usernames=['vincent', 'kevin', 'liang', 'bang']))

        from portal.vps.views import VpsModelView
        c = lazy_gettext('Vps')
        v = VpsModelView(Vps, db.session, endpoint='vps', category=c)
        root.add_view(v)
        root.add_link(RoleBasedMenuLink(
            name=lazy_gettext('Create'), category=c,
            endpoint='vps.create_view', roles=v.get_accessible_roles()))

        c = lazy_gettext('Vendor')
        from portal.vendor.views import VendorModelView
        v = VendorModelView(Vendor, db.session, endpoint='vendor', category=c)
        root.add_view(v)

        from portal.permission.views import PermissionModelView
        v = PermissionModelView(Permission, db.session, endpoint='permission', category=c)
        root.add_view(v)

        c = lazy_gettext('Finance')
        from portal.bank_account.views import BankAccountModelView
        v = BankAccountModelView(BankAccount, db.session, endpoint='bank_account', category=c)
        root.add_view(v)

        from portal.transfer.views import TransferModelView
        v = TransferModelView(Transfer, db.session, endpoint='transfer', category=c)
        root.add_view(v)

    return app