From 9d85c95584b2b95b1c0baee16864972880b26d01 Mon Sep 17 00:00:00 2001 From: Daniel Tsvetkov Date: Sat, 8 May 2021 15:52:52 +0200 Subject: [PATCH] permissions improvement --- oshipka/persistance/__init__.py | 22 ++++++++++++++++++++ vm_gen/templates/_model_py | 3 ++- vm_gen/templates/html/_action_create.html | 3 +++ vm_gen/templates/html/_action_delete.html | 4 +++- vm_gen/templates/html/_action_edit.html | 4 +++- vm_gen/templates/html/_action_list.html | 3 +++ vm_gen/templates/html/_action_search.html | 6 ++++++ vm_gen/templates/html/_action_table.html | 3 +++ vm_gen/templates/html/_actions.html | 11 ++++++---- vm_gen/templates/html/_actions_multiple.html | 2 ++ vm_gen/templates/html/_list_item.html | 7 ++++++- vm_gen/templates/html/_search.html | 5 +---- vm_gen/templates/html/_table.html | 3 +-- vm_gen/templates/html/get.html | 5 ++--- vm_gen/templates/html/list.html | 3 ++- vm_gen/templates/html/navigation.html | 2 +- vm_gen/templates/html/table.html | 2 +- vm_gen/vm_gen.py | 7 +++++-- 18 files changed, 73 insertions(+), 22 deletions(-) create mode 100644 vm_gen/templates/html/_action_create.html create mode 100644 vm_gen/templates/html/_action_list.html create mode 100644 vm_gen/templates/html/_action_search.html create mode 100644 vm_gen/templates/html/_action_table.html create mode 100644 vm_gen/templates/html/_actions_multiple.html diff --git a/oshipka/persistance/__init__.py b/oshipka/persistance/__init__.py index c217419..956570f 100644 --- a/oshipka/persistance/__init__.py +++ b/oshipka/persistance/__init__.py @@ -184,7 +184,9 @@ user_datastore = SQLAlchemyUserDatastore(db, User, Role) def register_filters(app): + # register jinja filters _paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}') + from oshipka.webapp.views import MODEL_VIEWS @app.template_filter('nl2br') def nl2br(text): @@ -234,6 +236,26 @@ def register_filters(app): def bool_filter(v): return bool(v) + def has_permission(model, verb, instance=None): + acl = MODEL_VIEWS.get(model, {}).model.acls.get(verb) + # Anonymous user -> do we require AuthN? + if current_user.is_anonymous: + return not acl.get('authn') + # Not Anonymous user -> Check roles + roles = acl.get('authz') + # No roles required -> has permission + if not roles: + return True + # One role is enough to grant permission + for role in roles: + if role in ['owner']: + return instance.user == current_user + if current_user.has_role(role): + return True + return False + + app.jinja_env.globals.update(has_permission=has_permission) + class Proxy(object): def __init__(self, proxied): diff --git a/vm_gen/templates/_model_py b/vm_gen/templates/_model_py index aa8ab79..963e006 100644 --- a/vm_gen/templates/_model_py +++ b/vm_gen/templates/_model_py @@ -6,7 +6,8 @@ class [[ name ]](db.Model, ModelController[% for inherit in interits %], [[ inhe [%- include "_model_choice_header_py" %] [%- include "_model_searchable_header_py" %] - _file_columns = [ [%- for column in columns %][%- if column.is_file %]"[[ column.name ]]"[%- endif %] [%- endfor %] ] + _file_columns = [ [%- for column in columns %][%- if column.is_file %]"[[ column.name ]]", [%- endif %] [%- endfor %] ] + acls = [[ acls ]] [%- for column in columns %] [%- if column._type == 'relationship' %] diff --git a/vm_gen/templates/html/_action_create.html b/vm_gen/templates/html/_action_create.html new file mode 100644 index 0000000..ae27d9c --- /dev/null +++ b/vm_gen/templates/html/_action_create.html @@ -0,0 +1,3 @@ +{% if has_permission('[[ name|camel_to_snake ]]', 'create', instance) %} +{{ _("Create") }} +{% endif %} \ No newline at end of file diff --git a/vm_gen/templates/html/_action_delete.html b/vm_gen/templates/html/_action_delete.html index 7592e8c..55fd47e 100644 --- a/vm_gen/templates/html/_action_delete.html +++ b/vm_gen/templates/html/_action_delete.html @@ -1 +1,3 @@ -x \ No newline at end of file +{% if has_permission('[[ name|camel_to_snake ]]', 'delete', instance) %} +x +{% endif %} \ No newline at end of file diff --git a/vm_gen/templates/html/_action_edit.html b/vm_gen/templates/html/_action_edit.html index 65f945f..2e6c91c 100644 --- a/vm_gen/templates/html/_action_edit.html +++ b/vm_gen/templates/html/_action_edit.html @@ -1 +1,3 @@ -e \ No newline at end of file +{% if has_permission('[[ name|camel_to_snake ]]', 'update', instance) %} +e +{% endif %} \ No newline at end of file diff --git a/vm_gen/templates/html/_action_list.html b/vm_gen/templates/html/_action_list.html new file mode 100644 index 0000000..3bba876 --- /dev/null +++ b/vm_gen/templates/html/_action_list.html @@ -0,0 +1,3 @@ +{% if has_permission('[[ name|camel_to_snake ]]', 'list') %} +{{ _("list") }} +{% endif %} \ No newline at end of file diff --git a/vm_gen/templates/html/_action_search.html b/vm_gen/templates/html/_action_search.html new file mode 100644 index 0000000..998e46f --- /dev/null +++ b/vm_gen/templates/html/_action_search.html @@ -0,0 +1,6 @@ +{% if has_permission('[[ name|camel_to_snake ]]', 'search') %} +
+ + +
+{% endif %} \ No newline at end of file diff --git a/vm_gen/templates/html/_action_table.html b/vm_gen/templates/html/_action_table.html new file mode 100644 index 0000000..698067e --- /dev/null +++ b/vm_gen/templates/html/_action_table.html @@ -0,0 +1,3 @@ +{% if has_permission('[[ name|camel_to_snake ]]', 'table') %} +{{ _("table") }} +{% endif %} \ No newline at end of file diff --git a/vm_gen/templates/html/_actions.html b/vm_gen/templates/html/_actions.html index bcf77ea..c234b29 100644 --- a/vm_gen/templates/html/_actions.html +++ b/vm_gen/templates/html/_actions.html @@ -1,4 +1,7 @@ -[ -{% include "[[ name|camel_to_snake ]]/_action_edit.html" %} | -{% include "[[ name|camel_to_snake ]]/_action_delete.html" %} -] \ No newline at end of file +{% if not has_permission('[[ name|camel_to_snake ]]', 'update', instance) and not has_permission('[[ name|camel_to_snake ]]', 'delete', instance) %} +{% else %} + [ + {% include "[[ name|camel_to_snake ]]/_action_edit.html" %} | + {% include "[[ name|camel_to_snake ]]/_action_delete.html" %} + ] +{% endif %} \ No newline at end of file diff --git a/vm_gen/templates/html/_actions_multiple.html b/vm_gen/templates/html/_actions_multiple.html new file mode 100644 index 0000000..ab0a357 --- /dev/null +++ b/vm_gen/templates/html/_actions_multiple.html @@ -0,0 +1,2 @@ +{% include "[[ name|camel_to_snake ]]/_action_list.html" %} | +{% include "[[ name|camel_to_snake ]]/_action_table.html" %} \ No newline at end of file diff --git a/vm_gen/templates/html/_list_item.html b/vm_gen/templates/html/_list_item.html index 738a70c..d99cf1d 100644 --- a/vm_gen/templates/html/_list_item.html +++ b/vm_gen/templates/html/_list_item.html @@ -1,5 +1,10 @@
  • + {% if has_permission('[[ name|camel_to_snake ]]', 'get') %} - {% include "[[ name|camel_to_snake ]]/_title.html" %} + {% endif %} + {% include "[[ name|camel_to_snake ]]/_title.html" %} + {% if has_permission('[[ name|camel_to_snake ]]', 'get') %} + + {% endif %} {% include "[[ name|camel_to_snake ]]/_actions.html" %}
  • \ No newline at end of file diff --git a/vm_gen/templates/html/_search.html b/vm_gen/templates/html/_search.html index 70a5b4f..0aee51d 100644 --- a/vm_gen/templates/html/_search.html +++ b/vm_gen/templates/html/_search.html @@ -3,9 +3,6 @@ {% include "[[ name|camel_to_snake ]]/_title.html" %} | - [ - e | - x - ] + {% include "[[ name|camel_to_snake ]]/_actions.html" %} {% endfor %} \ No newline at end of file diff --git a/vm_gen/templates/html/_table.html b/vm_gen/templates/html/_table.html index f8ddf41..78f06d6 100644 --- a/vm_gen/templates/html/_table.html +++ b/vm_gen/templates/html/_table.html @@ -28,8 +28,7 @@ {% endif %} [%- endfor %] - e | - x + {% include "[[ name|camel_to_snake ]]/_action.html" %} | {% endfor %} diff --git a/vm_gen/templates/html/get.html b/vm_gen/templates/html/get.html index 146636b..7b752c9 100644 --- a/vm_gen/templates/html/get.html +++ b/vm_gen/templates/html/get.html @@ -1,9 +1,8 @@ {% extends "layout.html" %} {% block content %} - {{ _("list") }} | + {% include "[[ name|camel_to_snake ]]/_actions_multiple.html" %}

    {% include "[[ name|camel_to_snake ]]/_title.html" %}

    - {{ _("edit") }} | - {{ _("delete") }} + {% include "[[ name|camel_to_snake ]]/_actions.html" %} {% include "[[ name|camel_to_snake ]]/_get.html" %} {% endblock %} \ No newline at end of file diff --git a/vm_gen/templates/html/list.html b/vm_gen/templates/html/list.html index 44cb72b..b16bf6d 100644 --- a/vm_gen/templates/html/list.html +++ b/vm_gen/templates/html/list.html @@ -2,7 +2,8 @@ {% block content %}

    {{ _("[[ name|pluralize ]]") }}

    - {{ _("Create") }} + {% include "[[ name|camel_to_snake ]]/_action_search.html" %} + {% include "[[ name|camel_to_snake ]]/_action_create.html" %}
    {% include "[[ name|camel_to_snake ]]/_list.html" %} {% endblock %} \ No newline at end of file diff --git a/vm_gen/templates/html/navigation.html b/vm_gen/templates/html/navigation.html index 836632a..a5f8938 100644 --- a/vm_gen/templates/html/navigation.html +++ b/vm_gen/templates/html/navigation.html @@ -1,7 +1,7 @@ {{ _("Home") }} | [%- for nav in navigation_items %] [%- if nav._verbs.list.is_login_required %] -{% if current_user.is_authenticated %} +{% if has_permission('[[ nav.name|camel_to_snake ]]', 'list') %} [%- endif %] {{ _("[[ nav.name ]]") }}[%- if not loop.last %]|[%- endif %] [%- if nav._verbs.list.is_login_required %] diff --git a/vm_gen/templates/html/table.html b/vm_gen/templates/html/table.html index b891f73..f37912c 100644 --- a/vm_gen/templates/html/table.html +++ b/vm_gen/templates/html/table.html @@ -2,7 +2,7 @@ {% block content %}

    {{ _("[[ name|pluralize ]]") }}

    - {{ _("Create") }} + {% include "[[ name|camel_to_snake ]]/_action_create.html" %}
    {% include "[[ name|camel_to_snake ]]/_table.html" %} {% endblock %} \ No newline at end of file diff --git a/vm_gen/vm_gen.py b/vm_gen/vm_gen.py index 3279c64..d65aec1 100644 --- a/vm_gen/vm_gen.py +++ b/vm_gen/vm_gen.py @@ -135,13 +135,13 @@ def enrich_view_model(view_model): 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') + 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') + view_model['_verbs'][verb]['the_roles_required'] = acl.get('roles_required', []) return view_model @@ -159,6 +159,9 @@ def process_navigation(view_models): def process_model(view_model): template = env.get_template('model_py') + view_model['acls'] = {} + for verb, acl in view_model['_verbs'].items(): + view_model['acls'][verb] = {'authn': acl['is_login_required'], 'authz': acl['the_roles_required']} model = autopep8.fix_code(template.render(**view_model), options=pep_options) _model_name = view_model.get('name')