finish implementing Flask_Security_Too and finished dynamic navbar creation.
This commit is contained in:
@@ -12,17 +12,18 @@ class Config(object):
|
|||||||
|
|
||||||
# flask-security-too settings
|
# flask-security-too settings
|
||||||
SECURITY_PASSWORD_SALT = '228614859439123264035565568761433607235'
|
SECURITY_PASSWORD_SALT = '228614859439123264035565568761433607235'
|
||||||
REMEMBER_COOKIE_SAMESITE = 'strict'
|
# REMEMBER_COOKIE_SAMESITE = 'strict'
|
||||||
SESSION_COOKIE_SAMESITE = 'strict'
|
# SESSION_COOKIE_SAMESITE = 'strict'
|
||||||
SECURITY_CONFIRMABLE = True
|
SECURITY_CONFIRMABLE = True
|
||||||
SECURITY_TRACKABLE = True
|
SECURITY_TRACKABLE = True
|
||||||
SECURITY_PASSWORD_COMPLEXITY_CHECKER = 'zxcvbn'
|
SECURITY_PASSWORD_COMPLEXITY_CHECKER = 'zxcvbn'
|
||||||
SECURITY_POST_LOGIN_VIEW = '/user/tenant'
|
SECURITY_POST_LOGIN_VIEW = '/user/tenant'
|
||||||
SECURITY_RECOVERABLE = True
|
SECURITY_RECOVERABLE = True
|
||||||
|
SECURITY_EMAIL_SENDER = "eveai_super@flow-it.net"
|
||||||
|
|
||||||
# flask-mailman settings
|
# flask-mailman settings
|
||||||
MAIL_SERVER = 'mail.flow-it.net'
|
MAIL_SERVER = 'mail.flow-it.net'
|
||||||
MAIL_PORT = 465
|
MAIL_PORT = 587
|
||||||
MAIL_USE_TLS = True
|
MAIL_USE_TLS = True
|
||||||
MAIL_USE_SSL = False
|
MAIL_USE_SSL = False
|
||||||
MAIL_DEFAULT_SENDER = ('eveAI Admin', 'eveai_admin@flow-it.net')
|
MAIL_DEFAULT_SENDER = ('eveAI Admin', 'eveai_admin@flow-it.net')
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_security import SQLAlchemyUserDatastore, current_user
|
from flask_security import SQLAlchemyUserDatastore
|
||||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||||
import logging.config
|
import logging.config
|
||||||
|
|
||||||
from .extensions import db, migrate, bootstrap, security, mail, login_manager
|
from .extensions import db, migrate, bootstrap, security, mail, login_manager
|
||||||
from .models.user import User, Tenant, Role
|
from .models.user import User, Tenant, Role
|
||||||
from .models.document import Document, DocumentLanguage, DocumentVersion
|
from .models.document import Document, DocumentLanguage, DocumentVersion
|
||||||
from logging_config import LOGGING
|
from .logging_config import LOGGING
|
||||||
|
# from .context_processors import inject_user
|
||||||
|
|
||||||
# Create app
|
# Create app
|
||||||
|
|
||||||
@@ -33,6 +34,8 @@ def create_app(config_file=None):
|
|||||||
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
|
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
|
||||||
security.init_app(app, user_datastore)
|
security.init_app(app, user_datastore)
|
||||||
|
|
||||||
|
# app.context_processor(inject_user)
|
||||||
|
|
||||||
# Register Blueprints
|
# Register Blueprints
|
||||||
register_blueprints(app)
|
register_blueprints(app)
|
||||||
|
|
||||||
@@ -40,6 +43,15 @@ def create_app(config_file=None):
|
|||||||
app.logger.setLevel(logging.DEBUG)
|
app.logger.setLevel(logging.DEBUG)
|
||||||
mail_logger = logging.getLogger('flask_mailman')
|
mail_logger = logging.getLogger('flask_mailman')
|
||||||
mail_logger.setLevel(logging.DEBUG)
|
mail_logger.setLevel(logging.DEBUG)
|
||||||
|
security_logger = logging.getLogger('flask_security')
|
||||||
|
security_logger.setLevel(logging.DEBUG)
|
||||||
|
# with app.app_context():
|
||||||
|
# mail.send_mail(
|
||||||
|
# subject="Dit is een debugging test",
|
||||||
|
# message="Die wordt enkel verzonden als de app in debug mode staat",
|
||||||
|
# from_email="eveai_super@flow-it.net",
|
||||||
|
# recipient_list=["eveai_super@flow-it.net"],
|
||||||
|
# )
|
||||||
|
|
||||||
# Register API
|
# Register API
|
||||||
register_api(app)
|
register_api(app)
|
||||||
|
|||||||
9
eveai_app/context_processors.py
Normal file
9
eveai_app/context_processors.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from flask_security import current_user
|
||||||
|
|
||||||
|
|
||||||
|
# def inject_user():
|
||||||
|
# if current_user:
|
||||||
|
# print("Injecting current_user: ", current_user)
|
||||||
|
# else:
|
||||||
|
# print("No user to inject")
|
||||||
|
# return {'current_user': current_user}
|
||||||
@@ -64,6 +64,7 @@ class User(db.Model, UserMixin):
|
|||||||
first_name = db.Column(db.String(80), nullable=False)
|
first_name = db.Column(db.String(80), nullable=False)
|
||||||
last_name = db.Column(db.String(80), nullable=False)
|
last_name = db.Column(db.String(80), nullable=False)
|
||||||
is_active = db.Column(db.Boolean, default=True)
|
is_active = db.Column(db.Boolean, default=True)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
fs_uniquifier = db.Column(db.String(255), unique=True, nullable=False)
|
fs_uniquifier = db.Column(db.String(255), unique=True, nullable=False)
|
||||||
confirmed_at = db.Column(db.DateTime, nullable=True)
|
confirmed_at = db.Column(db.DateTime, nullable=True)
|
||||||
valid_to = db.Column(db.Date, nullable=True)
|
valid_to = db.Column(db.Date, nullable=True)
|
||||||
@@ -80,5 +81,8 @@ class User(db.Model, UserMixin):
|
|||||||
tenant_id = db.Column(db.Integer, db.ForeignKey('public.tenant.id'), nullable=False)
|
tenant_id = db.Column(db.Integer, db.ForeignKey('public.tenant.id'), nullable=False)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<User %r>' % self.name()
|
return '<User %r>' % self.user_name
|
||||||
|
|
||||||
|
def has_roles(self, *args):
|
||||||
|
return any(role.name in args for role in self.roles)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<header class="header-2">
|
<header class="header-2">
|
||||||
<div class="page-header min-vh-75" style="background-image: url({{url_for('static', filename='/assets/img/EveAI_bg2.jpg')}})" loading="lazy">
|
<div class="page-header min-vh-25" style="background-image: url({{url_for('static', filename='/assets/img/EveAI_bg2.jpg')}})" loading="lazy">
|
||||||
<span class="mask bg-gradient-primary opacity-4"></span>
|
<span class="mask bg-gradient-primary opacity-4"></span>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -1,4 +1,46 @@
|
|||||||
{% from "navbar_macros.html" import nav_link, dropdown %}
|
{% macro nav_link(name, url, icon=None) %}
|
||||||
|
<li class="nav-item mx-2">
|
||||||
|
<a class="nav-link" href="{{ url }}">
|
||||||
|
{% if icon %}
|
||||||
|
<i class="material-icons">{{ icon }}</i>
|
||||||
|
{% endif %}
|
||||||
|
{{ name }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro dropdown(title, icon, children) %}
|
||||||
|
<li class="nav-item dropdown dropdown-hover mx-2">
|
||||||
|
<a role="button" class="nav-link ps-2 d-flex cursor-pointer align-items-center" id="{{ title | replace(' ', '') }}" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
{% if icon %}
|
||||||
|
<i class="material-icons opacity-6 me-2 text-md">{{ icon }}</i>
|
||||||
|
{% endif %}
|
||||||
|
{{ title }}
|
||||||
|
<img src="{{ url_for('static', filename='assets/img/down-arrow-dark.svg') }}" alt="down-arrow" class="arrow ms-2">
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdown-menu-animation" aria-labelledby="{{ title | replace(' ', '') }}">
|
||||||
|
<ul class="list-group w-100">
|
||||||
|
{% for child in children %}
|
||||||
|
{% if child.roles %}
|
||||||
|
{% if current_user.has_roles(*child.roles) %}
|
||||||
|
<li class="nav-item dropdown-subitem list-group-item border-0 p-0">
|
||||||
|
<a class="dropdown-item ps-3 border-radius-md mb-1" href="{{ child.url }}">
|
||||||
|
<span>{{ child.name }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-item dropdown-subitem list-group-item border-0 p-0">
|
||||||
|
<a class="dropdown-item ps-3 border-radius-md mb-1" href="{{ child.url }}">
|
||||||
|
<span>{{ child.name }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
<div class="navbar navbar-expand-lg navbar-light bg-white z-index-3 py-3">
|
<div class="navbar navbar-expand-lg navbar-light bg-white z-index-3 py-3">
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime as dt, timezone as tz
|
from datetime import datetime as dt, timezone as tz
|
||||||
from flask import request, redirect, url_for, flash, render_template, Blueprint, session
|
from flask import request, redirect, url_for, flash, render_template, Blueprint, session
|
||||||
from flask_security import hash_password, current_user
|
from flask_security import hash_password, current_user, login_required, roles_required, roles_accepted
|
||||||
|
|
||||||
from ..models.user import User, Tenant, Role, RolesUsers
|
from ..models.user import User, Tenant, Role, RolesUsers
|
||||||
from ..extensions import db
|
from ..extensions import db
|
||||||
@@ -13,6 +13,7 @@ user_bp = Blueprint('user_bp', __name__, url_prefix='/user')
|
|||||||
|
|
||||||
|
|
||||||
@user_bp.route('/tenant', methods=['GET', 'POST'])
|
@user_bp.route('/tenant', methods=['GET', 'POST'])
|
||||||
|
@roles_required('Super User')
|
||||||
def tenant():
|
def tenant():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
# Handle the required attributes
|
# Handle the required attributes
|
||||||
@@ -65,6 +66,7 @@ def tenant():
|
|||||||
|
|
||||||
|
|
||||||
@user_bp.route('/tenant/<int:tenant_id>', methods=['GET', 'POST'])
|
@user_bp.route('/tenant/<int:tenant_id>', methods=['GET', 'POST'])
|
||||||
|
@roles_required('Super User')
|
||||||
def edit_tenant(tenant_id):
|
def edit_tenant(tenant_id):
|
||||||
tenant = Tenant.query.get_or_404(tenant_id) # This will return a 404 if no tenant is found
|
tenant = Tenant.query.get_or_404(tenant_id) # This will return a 404 if no tenant is found
|
||||||
form = TenantForm(obj=tenant)
|
form = TenantForm(obj=tenant)
|
||||||
@@ -80,6 +82,7 @@ def edit_tenant(tenant_id):
|
|||||||
|
|
||||||
|
|
||||||
@user_bp.route('/user', methods=['GET', 'POST'])
|
@user_bp.route('/user', methods=['GET', 'POST'])
|
||||||
|
@roles_accepted('Super User', 'Tenant Admin')
|
||||||
def user():
|
def user():
|
||||||
form = CreateUserForm()
|
form = CreateUserForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
@@ -129,6 +132,7 @@ def user():
|
|||||||
|
|
||||||
|
|
||||||
@user_bp.route('/user/<int:user_id>', methods=['GET', 'POST'])
|
@user_bp.route('/user/<int:user_id>', methods=['GET', 'POST'])
|
||||||
|
@roles_accepted('Super User', 'Tenant Admin')
|
||||||
def edit_user(user_id):
|
def edit_user(user_id):
|
||||||
user = User.query.get_or_404(user_id) # This will return a 404 if no user is found
|
user = User.query.get_or_404(user_id) # This will return a 404 if no user is found
|
||||||
form = EditUserForm(obj=user)
|
form = EditUserForm(obj=user)
|
||||||
@@ -165,12 +169,14 @@ def edit_user(user_id):
|
|||||||
|
|
||||||
|
|
||||||
@user_bp.route('/select_tenant')
|
@user_bp.route('/select_tenant')
|
||||||
|
@roles_required('Super User')
|
||||||
def select_tenant():
|
def select_tenant():
|
||||||
tenants = Tenant.query.all() # Fetch all tenants from the database
|
tenants = Tenant.query.all() # Fetch all tenants from the database
|
||||||
return render_template('user/select_tenant.html', tenants=tenants)
|
return render_template('user/select_tenant.html', tenants=tenants)
|
||||||
|
|
||||||
|
|
||||||
@user_bp.route('/handle_tenant_selection', methods=['POST'])
|
@user_bp.route('/handle_tenant_selection', methods=['POST'])
|
||||||
|
@roles_required('Super User')
|
||||||
def handle_tenant_selection():
|
def handle_tenant_selection():
|
||||||
tenant_id = request.form['tenant_id']
|
tenant_id = request.form['tenant_id']
|
||||||
session['tenant_id'] = request.form['tenant_id']
|
session['tenant_id'] = request.form['tenant_id']
|
||||||
@@ -185,6 +191,7 @@ def handle_tenant_selection():
|
|||||||
|
|
||||||
|
|
||||||
@user_bp.route('/view_users/<tenant_id>')
|
@user_bp.route('/view_users/<tenant_id>')
|
||||||
|
@roles_accepted('Super User', 'Tenant Admin')
|
||||||
def view_users(tenant_id):
|
def view_users(tenant_id):
|
||||||
print(tenant_id)
|
print(tenant_id)
|
||||||
tenant_id = int(tenant_id)
|
tenant_id = int(tenant_id)
|
||||||
@@ -195,6 +202,7 @@ def view_users(tenant_id):
|
|||||||
|
|
||||||
|
|
||||||
@user_bp.route('/handle_user_action', methods=['POST'])
|
@user_bp.route('/handle_user_action', methods=['POST'])
|
||||||
|
@roles_accepted('Super User', 'Tenant Admin')
|
||||||
def handle_user_action():
|
def handle_user_action():
|
||||||
user_id = request.form['user_id']
|
user_id = request.form['user_id']
|
||||||
action = request.form['action']
|
action = request.form['action']
|
||||||
|
|||||||
Reference in New Issue
Block a user