enable ACLs - users and roles
This commit is contained in:
parent
93cee58cfb
commit
61743a5050
1
bootstrap/data_static/Role.csv
Normal file
1
bootstrap/data_static/Role.csv
Normal file
@ -0,0 +1 @@
|
||||
name
|
|
1
bootstrap/data_static/User.csv
Normal file
1
bootstrap/data_static/User.csv
Normal file
@ -0,0 +1 @@
|
||||
email,password,role_names
|
|
@ -0,0 +1,2 @@
|
||||
Role
|
||||
User
|
@ -13,6 +13,7 @@ from flask_migrate import upgrade as migrate_upgrade
|
||||
from flask_migrate import init as migrate_init
|
||||
from flask_security import RoleMixin, UserMixin
|
||||
from flask_security import Security, SQLAlchemyUserDatastore
|
||||
from flask_security.utils import encrypt_password, hash_password
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from markupsafe import escape, Markup
|
||||
from sqlalchemy import Boolean
|
||||
@ -266,15 +267,38 @@ def init_db(app):
|
||||
return rv
|
||||
|
||||
|
||||
SENSITIVE_PREFIX = "__SENSITIVE__."
|
||||
|
||||
|
||||
def populate_static(app):
|
||||
with app.app_context():
|
||||
models = import_module("webapp.models")
|
||||
sensitive = import_module("sensitive")
|
||||
ordered_model_names = order_from_process_order('csv', STATIC_DATA_DIR)
|
||||
for model_name in ordered_model_names:
|
||||
model = getattr(models, model_name)
|
||||
if model_name in ['User', 'Role']:
|
||||
model = eval(model_name)
|
||||
else:
|
||||
model = getattr(models, model_name)
|
||||
with open(os.path.join(STATIC_DATA_DIR, "{}.csv".format(model_name))) as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
instance = model(**row)
|
||||
db.session.add(instance)
|
||||
row_updates = dict()
|
||||
for key, value in row.items():
|
||||
if value.startswith(SENSITIVE_PREFIX):
|
||||
sensitive_key = SENSITIVE_PREFIX.join(value.split(SENSITIVE_PREFIX)[1:])
|
||||
sensitive_value = getattr(sensitive, sensitive_key)
|
||||
row_updates[key] = sensitive_value
|
||||
if row_updates:
|
||||
row.update(row_updates)
|
||||
if model_name == "User":
|
||||
role_names = row.pop('role_names')
|
||||
row['password'] = hash_password(row['password'])
|
||||
user = user_datastore.create_user(**row)
|
||||
for role_name in role_names.split(';'):
|
||||
role = Role.query.filter_by(name=role_name).first()
|
||||
user_datastore.add_role_to_user(user, role)
|
||||
else:
|
||||
instance = model(**row)
|
||||
db.session.add(instance)
|
||||
db.session.commit()
|
||||
|
@ -1,9 +1,10 @@
|
||||
import importlib
|
||||
from copy import deepcopy, copy
|
||||
from copy import copy
|
||||
from functools import wraps
|
||||
|
||||
import inflect
|
||||
from flask import flash, render_template, redirect, request, url_for, jsonify
|
||||
from flask_security import login_required, roles_required
|
||||
|
||||
from oshipka.persistance import db
|
||||
from oshipka.util.strings import camel_case_to_snake_case
|
||||
@ -172,8 +173,9 @@ class ViewContext(object):
|
||||
self.redirect_next = None
|
||||
|
||||
|
||||
def create_view(model_view, view_context, **kwargs):
|
||||
def create_view(model_view, view_context, is_login_required=False, the_roles_required=None, **kwargs):
|
||||
view_context.model_view = model_view
|
||||
the_roles_required = [] if not the_roles_required else the_roles_required
|
||||
|
||||
def return_json_or_template():
|
||||
if view_context.is_json:
|
||||
@ -212,6 +214,10 @@ def create_view(model_view, view_context, **kwargs):
|
||||
return view_context.redirect_func(view_context)
|
||||
|
||||
return return_json_or_template()
|
||||
if is_login_required:
|
||||
if the_roles_required:
|
||||
inner = roles_required(*the_roles_required)(inner)
|
||||
return login_required(inner)
|
||||
|
||||
return inner
|
||||
|
||||
@ -269,7 +275,7 @@ def catch_flash(f):
|
||||
return f(*args, **kwargs)
|
||||
except Exception as e:
|
||||
flash(str(e), "error")
|
||||
serialized_form = serialize_form()
|
||||
serialized_form = {k: v for k, v in request.form.items()}
|
||||
if '_next' in serialized_form:
|
||||
_next = serialized_form.pop('_next')
|
||||
elif request.referrer and request.referrer != request.path:
|
||||
|
@ -10,10 +10,12 @@ from webapp.models import [[ name ]]
|
||||
from webapp.routes.[[ name|camel_to_snake ]]_hooks import *
|
||||
|
||||
[[ name|camel_to_snake ]] = ModelView(app, [[name]])
|
||||
[[ name|camel_to_snake ]].register_verb(view_context=get_view_context, verb="get", per_item=True)
|
||||
[[ name|camel_to_snake ]].register_verb(view_context=list_view_context, verb="list")
|
||||
[[ name|camel_to_snake ]].register_verb(view_context=table_view_context, verb="table")
|
||||
[[ name|camel_to_snake ]].register_verb(view_context=search_view_context, verb="search")
|
||||
[[ name|camel_to_snake ]].register_verb(view_context=create_view_context, verb="create", methods=["GET", "POST"])
|
||||
[[ name|camel_to_snake ]].register_verb(view_context=update_view_context, verb="update", methods=["GET", "POST"], per_item=True)
|
||||
[[ name|camel_to_snake ]].register_verb(view_context=delete_view_context, verb="delete", methods=["GET", "POST"] , per_item=True)
|
||||
[% for verb, verb_values in _verbs.items() %]
|
||||
[[ name|camel_to_snake ]].register_verb(view_context=[[ verb ]]_view_context,
|
||||
verb="[[ verb ]]",
|
||||
methods=[[ verb_values.methods ]],
|
||||
per_item=[[ verb_values.per_item ]],
|
||||
is_login_required=[[ verb_values.is_login_required if verb_values.is_login_required else 'False' ]],
|
||||
the_roles_required=[[ verb_values.the_roles_required if verb_values.the_roles_required else '[]' ]],
|
||||
)
|
||||
[% endfor %]
|
||||
|
@ -37,6 +37,38 @@ def process_secondary(view_model, column_name):
|
||||
}
|
||||
|
||||
|
||||
VERBS = {
|
||||
'get': {
|
||||
'per_item': 'True',
|
||||
'methods': ['GET'],
|
||||
},
|
||||
'list': {
|
||||
'per_item': 'False',
|
||||
'methods': ['GET'],
|
||||
},
|
||||
'table': {
|
||||
'per_item': 'False',
|
||||
'methods': ['GET'],
|
||||
},
|
||||
'search': {
|
||||
'per_item': 'False',
|
||||
'methods': ['GET'],
|
||||
},
|
||||
'create': {
|
||||
'per_item': 'False',
|
||||
'methods': ['GET', 'POST'],
|
||||
},
|
||||
'update': {
|
||||
'per_item': 'True',
|
||||
'methods': ['GET', 'POST'],
|
||||
},
|
||||
'delete': {
|
||||
'per_item': 'True',
|
||||
'methods': ['GET', 'POST'],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def enrich_view_model(view_model):
|
||||
columns = []
|
||||
for column in view_model.get('columns', {}):
|
||||
@ -48,6 +80,8 @@ def enrich_view_model(view_model):
|
||||
_column_type = 'db.Integer'
|
||||
elif column_type in ['bool', ] or column_name.startswith('is_'):
|
||||
_column_type = 'LiberalBoolean'
|
||||
elif column_type in ['datetime', ] or column_name.endswith('_dt'):
|
||||
_column_type = 'db.UnicodeText'
|
||||
elif column_type in ['relationship', ]:
|
||||
_column_type = 'relationship'
|
||||
multiple = column.get('multiple')
|
||||
@ -68,6 +102,25 @@ def enrich_view_model(view_model):
|
||||
column.update({'_type': _column_type})
|
||||
columns.append(column)
|
||||
view_model['columns'] = columns
|
||||
|
||||
view_model['_verbs'] = {}
|
||||
for verb, verb_default in VERBS.items():
|
||||
view_model['_verbs'][verb] = verb_default
|
||||
|
||||
access = view_model.get('access')
|
||||
if access:
|
||||
for acl in access:
|
||||
verb = acl.get('verb')
|
||||
if verb == 'all':
|
||||
for verb in VERBS:
|
||||
view_model['_verbs'][verb]['is_login_required'] = acl.get('login_required')
|
||||
view_model['_verbs'][verb]['the_roles_required'] = acl.get('roles_required')
|
||||
else:
|
||||
is_login_required = acl.get('login_required')
|
||||
if is_login_required is False: # overrides all
|
||||
view_model['_verbs'][verb]['the_roles_required'] = acl.get('login_required')
|
||||
view_model['_verbs'][verb]['is_login_required'] = is_login_required
|
||||
view_model['_verbs'][verb]['the_roles_required'] = acl.get('roles_required')
|
||||
return view_model
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user