Skip to content
Snippets Groups Projects
Commit 01069bc5 authored by kaiyou's avatar kaiyou
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
require('./app.css');
// jQuery
import jQuery from 'jquery';
// bootstrap
import 'bootstrap/less/bootstrap.less';
import 'bootstrap';
// FA
import 'font-awesome/scss/font-awesome.scss';
// AdminLTE
import 'admin-lte/build/less/AdminLTE-without-plugins.less';
import 'admin-lte/build/less/select2.less';
import 'admin-lte/build/less/skins/skin-red.less';
import 'admin-lte/build/js/Layout.js';
import 'admin-lte/build/js/ControlSidebar.js';
import 'admin-lte/build/js/PushMenu.js';
import 'admin-lte/build/js/BoxRefresh.js';
Generic single-database configuration.
\ No newline at end of file
# A generic, single database configuration.
[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
from __future__ import with_statement
import logging
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from flask import current_app
config.set_main_option(
'sqlalchemy.url', current_app.config.get(
'SQLALCHEMY_DATABASE_URI').replace('%', '%%'))
target_metadata = current_app.extensions['migrate'].db.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=target_metadata, literal_binds=True
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}
{
"name": "trurt",
"version": "1.0.0",
"description": "TRURT",
"main": "assest/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@babel/core": "^7.4.4",
"@babel/preset-env": "^7.4.4",
"admin-lte": "^2.4.10",
"babel-loader": "^8.0.5",
"bootstrap": "^3.4.1",
"css-loader": "^2.1.1",
"expose-loader": "^0.7.5",
"file-loader": "^3.0.1",
"font-awesome": "^4.7.0",
"font-awesome-loader": "^1.0.2",
"jQuery": "^1.7.4",
"less": "^3.9.0",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.6.0",
"node-sass": "^4.12.0",
"popper.js": "^1.15.0",
"sass-loader": "^7.1.0",
"select2": "^4.0.7-rc.0",
"style-loader": "^0.23.1",
"url-loader": "^1.1.2",
"webpack": "^4.30.0",
"webpack-cli": "^3.3.2"
}
}
import flask
from trurt import models, manage, configuration, debug, utils
def create_app_from_config(config):
""" Create a new application based on the given configuration
"""
app = flask.Flask(__name__)
app.cli.add_command(manage.trurt)
# Initialize application extensions
config.init_app(app)
models.db.init_app(app)
utils.limiter.init_app(app)
utils.babel.init_app(app)
utils.login.init_app(app)
utils.login.user_loader(models.User.get)
utils.migrate.init_app(app, models.db)
# Initialize debugging tools
if app.config.get("DEBUG"):
debug.toolbar.init_app(app)
# TODO: add a specific configuration variable for profiling
# debug.profiler.init_app(app)
# Inject the default variables in the Jinja parser
@app.context_processor
def inject_defaults():
return dict(config=app.config)
# Import views
from trurt import account
app.register_blueprint(account.account, url_prefix='/account')
return app
def create_app():
""" Create a new application based on the config module
"""
config = configuration.ConfigManager()
return create_app_from_config(config)
from flask import Blueprint
account = Blueprint('account', __name__)
from trurt.account import *
import os
DEFAULT_CONFIG = {
# Common configuration variables
'DEBUG': False,
'BABEL_DEFAULT_LOCALE': 'en',
'BABEL_DEFAULT_TIMEZONE': 'UTC',
'SQLALCHEMY_DATABASE_URI': 'sqlite:///./trurt.db',
'SQLALCHEMY_TRACK_MODIFICATIONS': False,
'SECRET_KEY': 'changeMe',
}
class ConfigManager(dict):
""" Naive configuration manager that uses environment only
"""
def __init__(self):
self.config = dict()
def __coerce_value(self, value):
if isinstance(value, str) and value.lower() in ('true','yes'):
return True
elif isinstance(value, str) and value.lower() in ('false', 'no'):
return False
return value
def init_app(self, app):
self.config.update(app.config)
# get environment variables
self.config.update({
key: self.__coerce_value(os.environ.get(key, value))
for key, value in DEFAULT_CONFIG.items()
})
# update the app config itself
app.config = self
def setdefault(self, key, value):
if key not in self.config:
self.config[key] = value
return self.config[key]
def get(self, *args):
return self.config.get(*args)
def keys(self):
return self.config.keys()
def __getitem__(self, key):
return self.config.get(key)
def __setitem__(self, key, value):
self.config[key] = value
def __contains__(self, key):
return key in self.config
import flask_debugtoolbar
from werkzeug.contrib import profiler as werkzeug_profiler
# Debugging toolbar
toolbar = flask_debugtoolbar.DebugToolbarExtension()
# Profiler
class Profiler(object):
def init_app(self, app):
app.wsgi_app = werkzeug_profiler.ProfilerMiddleware(
app.wsgi_app, restrictions=[30]
)
profiler = Profiler()
from flask import current_app as app
from flask import cli as flask_cli
import flask
import click
@click.group()
def trurt(cls=flask_cli.FlaskGroup):
""" Trurt command line
"""
from sqlalchemy.ext import declarative
from passlib import context, hash
from datetime import datetime, date
from flask import current_app as app
import flask_sqlalchemy
import sqlalchemy
import time
import os
import glob
db = flask_sqlalchemy.SQLAlchemy()
class JSONEncoded(db.TypeDecorator):
""" Represents an immutable structure as a json-encoded string.
"""
impl = db.String
def process_bind_param(self, value, dialect):
return json.dumps(value) if value else None
def process_result_value(self, value, dialect):
return json.loads(value) if value else None
class Base(db.Model):
""" Base class for all models
"""
__abstract__ = True
metadata = sqlalchemy.schema.MetaData(
naming_convention={
"fk": "%(table_name)s_%(column_0_name)s_fkey",
"pk": "%(table_name)s_pkey"
}
)
id = db.Column(db.Integer(), primary_key=True)
created_at = db.Column(db.Date, nullable=False, default=date.today)
updated_at = db.Column(db.Date, nullable=True, onupdate=date.today)
comment = db.Column(db.String(255), nullable=True)
class User(Base):
""" A user is the local representation of an authenticated person.
"""
__tablename__ = "user"
username = db.Column(db.String(255), nullable=False, unique=True)
# Flask-login attributes
is_authenticated = True
is_active = True
is_anonymous = False
def get(cls, id):
return cls.query.get(id)
def get_id(self):
return self.id
class Auth(Base):
""" An authenticator is a method to authenticate a user.
"""
__tablename__ = "auth"
user_username = db.Column(db.Integer(), db.ForeignKey(User.id))
user = db.relationship(User,
backref=db.backref('auths', cascade='all, delete-orphan'))
# TODO: support multiple authentication realms, therefore more than
# passwords
value = db.Column(db.String)
extra = db.Column(JSONEncoded)
class Service(Base):
""" A service is a client application (SP or RP typically).
"""
__tablename__ = "service"
spn = db.Column(db.String(255), unique=True)
protocol = db.Column(db.String(25))
config = db.Column(JSONEncoded)
class Profile(Base):
""" A profile is a user instance for a given service.
"""
__tablename__ = "profile"
username = db.Column(db.String(255), nullable=False)
user = db.relationship(User,
backref=db.backref('profiles', cascade='all, delete-orphan'))
service = db.relationship(Service,
backref=db.backref('profiles', cascade='all, delete-orphan'))
import flask
import flask_login
import flask_migrate
import flask_babel
import flask_limiter
from werkzeug.contrib import fixers
# Login configuration
login = flask_login.LoginManager()
login.login_view = "account.login"
@login.unauthorized_handler
def handle_needs_login():
return flask.redirect(
flask.url_for('account.login', next=flask.request.endpoint)
)
# Request rate limitation
limiter = flask_limiter.Limiter(key_func=lambda: current_user.id)
# Application translation
babel = flask_babel.Babel()
@babel.localeselector
def get_locale():
translations = list(map(str, babel.list_translations()))
return flask.request.accept_languages.best_match(translations)
# Data migrate
migrate = flask_migrate.Migrate()
var path = require("path");
var webpack = require("webpack");
var css = require("mini-css-extract-plugin");
module.exports = {
mode: "development",
entry: {
app: "./assets/app.js",
vendor: "./assets/vendor.js"
},
output: {
path: path.resolve(__dirname, "static/"),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader']
},
{
test: /\.scss$/,
use: [css.loader, 'css-loader', 'sass-loader']
},
{
test: /\.less$/,
use: [css.loader, 'css-loader', 'less-loader']
},
{
test: /\.css$/,
use: [css.loader, 'css-loader']
},
{
test: /\.woff($|\?)|\.woff2($|\?)|\.ttf($|\?)|\.eot($|\?)|\.svg($|\?)/,
use: ['url-loader']
},
{
// Exposes jQuery for use outside Webpack build
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: 'jQuery'
}, {
loader: 'expose-loader',
options: '$'
}]
}
]
},
plugins: [
new css({
filename: "[name].css",
chunkFilename: "[id].css"
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment