- Add 'Partner Admin' role to actual functionality in eveai_app
This commit is contained in:
71
common/services/tenant_service.py
Normal file
71
common/services/tenant_service.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from flask import session, current_app
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from common.extensions import db
|
||||
from common.models.user import Partner, PartnerTenant
|
||||
from common.utils.eveai_exceptions import EveAINoManagementPartnerService
|
||||
from common.utils.model_logging_utils import set_logging_information
|
||||
from datetime import datetime as dt, timezone as tz
|
||||
|
||||
from common.utils.security_utils import current_user_has_role
|
||||
|
||||
|
||||
class TenantService:
|
||||
@staticmethod
|
||||
def associate_tenant_with_partner(tenant_id):
|
||||
"""Associate a tenant with a partner"""
|
||||
try:
|
||||
partner_id = session['partner']['id']
|
||||
# Get partner service (MANAGEMENT_SERVICE type)
|
||||
partner = Partner.query.get(partner_id)
|
||||
if not partner:
|
||||
return
|
||||
|
||||
# Find a management service for this partner
|
||||
management_service = next((service for service in session['partner']['services']
|
||||
if service.get('type') == 'MANAGEMENT_SERVICE'), None)
|
||||
|
||||
if not management_service:
|
||||
current_app.logger.error(f"No Management Service defined for partner {partner_id}"
|
||||
f"while associating tenant {tenant_id} with partner.")
|
||||
raise EveAINoManagementPartnerService()
|
||||
|
||||
# Create the association
|
||||
tenant_partner = PartnerTenant(
|
||||
partner_service_id=management_service['id'],
|
||||
tenant_id=tenant_id,
|
||||
relationship_type='MANAGED',
|
||||
)
|
||||
set_logging_information(tenant_partner, dt.now(tz.utc))
|
||||
|
||||
db.session.add(tenant_partner)
|
||||
db.session.commit()
|
||||
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback()
|
||||
current_app.logger.error(f"Error associating tenant {tenant_id} with partner: {str(e)}")
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def can_user_edit_tenant(tenant_id) -> bool:
|
||||
if current_user_has_role('Super User'):
|
||||
return True
|
||||
elif current_user_has_role('Partner Admin'):
|
||||
partner_id = session['partner']['id']
|
||||
partner_service = next((service for service in session['partner']['services']
|
||||
if service.get('type') == 'MANAGEMENT_SERVICE'), None)
|
||||
if not partner_service:
|
||||
return False
|
||||
else:
|
||||
partner_tenant = PartnerTenant.query.filter(
|
||||
PartnerTenant.tenant_id == tenant_id,
|
||||
PartnerTenant.partner_service_id == partner_service['id'],
|
||||
).first()
|
||||
if partner_tenant:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
@@ -14,16 +14,13 @@ class UserService:
|
||||
and the active tenant for the session"""
|
||||
current_tenant_id = session.get('tenant').get('id', None)
|
||||
effective_role_names = []
|
||||
if current_tenant_id:
|
||||
if current_user_has_role("Super User"):
|
||||
if current_tenant_id == 1:
|
||||
if current_user_has_role("Super User"):
|
||||
effective_role_names.append("Super User")
|
||||
if session.get('partner'):
|
||||
effective_role_names.append("Partner Admin")
|
||||
effective_role_names.append("Tenant Admin")
|
||||
elif current_tenant_id:
|
||||
if current_user_has_role("Tenant Admin"):
|
||||
effective_role_names.append("Tenant Admin")
|
||||
if current_user_has_role("Partner Admin"):
|
||||
if current_user_has_role("Partner Admin") or current_user_has_role("Super User"):
|
||||
effective_role_names.append("Tenant Admin")
|
||||
if session.get('partner'):
|
||||
if session.get('partner').get('tenant_id') == current_tenant_id:
|
||||
@@ -32,8 +29,6 @@ class UserService:
|
||||
effective_roles = [(role.id, role.name) for role in
|
||||
Role.query.filter(Role.name.in_(effective_role_names)).all()]
|
||||
return effective_roles
|
||||
else:
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def validate_role_assignments(role_ids):
|
||||
|
||||
@@ -154,3 +154,35 @@ class EveAIRoleAssignmentException(EveAIException):
|
||||
def __init__(self, message, status_code=403, payload=None):
|
||||
super().__init__(message, status_code, payload)
|
||||
|
||||
|
||||
class EveAINoManagementPartnerService(EveAIException):
|
||||
"""Exception raised when the operation requires the logged in partner (or selected parter by Super User)
|
||||
does not have a MANAGEMENT_SERVICE"""
|
||||
|
||||
def __init__(self, message="No Management Service defined for partner", status_code=403, payload=None):
|
||||
super().__init__(message, status_code, payload)
|
||||
|
||||
|
||||
class EveAINoSessionTenant(EveAIException):
|
||||
"""Exception raised when no session tenant is set"""
|
||||
|
||||
def __init__(self, message="No Session Tenant selected. Cannot perform requested action.", status_code=403,
|
||||
payload=None):
|
||||
super().__init__(message, status_code, payload)
|
||||
|
||||
|
||||
class EveAINoSessionPartner(EveAIException):
|
||||
"""Exception raised when no session partner is set"""
|
||||
|
||||
def __init__(self, message="No Session Partner selected. Cannot perform requested action.", status_code=403,
|
||||
payload=None):
|
||||
super().__init__(message, status_code, payload)
|
||||
|
||||
|
||||
class EveAINoManagementPartnerForTenant(EveAIException):
|
||||
"""Exception raised when the selected partner is no management partner for tenant"""
|
||||
|
||||
def __init__(self, message="No Management Partner for Tenant", status_code=403, payload=None):
|
||||
super().__init__(message, status_code, payload)
|
||||
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@ for handling tenant requests
|
||||
|
||||
from flask_security import current_user
|
||||
from flask import session, current_app, redirect
|
||||
from common.utils.nginx_utils import prefixed_url_for
|
||||
|
||||
from .database import Database
|
||||
from .eveai_exceptions import EveAINoSessionTenant, EveAINoSessionPartner, EveAINoManagementPartnerService, \
|
||||
EveAINoManagementPartnerForTenant
|
||||
from ..services.tenant_service import TenantService
|
||||
|
||||
|
||||
def mw_before_request():
|
||||
@@ -17,17 +18,27 @@ def mw_before_request():
|
||||
"""
|
||||
|
||||
if 'tenant' not in session:
|
||||
current_app.logger.warning('No tenant defined in session')
|
||||
return redirect(prefixed_url_for('security_bp.login'))
|
||||
raise EveAINoSessionTenant()
|
||||
|
||||
tenant_id = session['tenant']['id']
|
||||
if not tenant_id:
|
||||
raise Exception('Cannot switch schema for tenant: no tenant defined in session')
|
||||
raise EveAINoSessionTenant()
|
||||
|
||||
switch_allowed = False
|
||||
if current_user.has_role('Super User'):
|
||||
switch_allowed = True
|
||||
if current_user.has_role('Tenant Admin') and current_user.tenant_id == tenant_id:
|
||||
switch_allowed = True
|
||||
if current_user.has_role('Partner Admin'):
|
||||
if 'partner' not in session:
|
||||
raise EveAINoSessionPartner()
|
||||
management_service = next((service for service in session['partner']['services']
|
||||
if service.get('type') == 'MANAGEMENT_SERVICE'), None)
|
||||
if not management_service:
|
||||
raise EveAINoManagementPartnerService()
|
||||
if not TenantService.can_user_edit_tenant(tenant_id):
|
||||
raise EveAINoManagementPartnerForTenant()
|
||||
|
||||
# user = User.query.get(current_user.id)
|
||||
if current_user.has_role('Super User') or current_user.tenant_id == tenant_id:
|
||||
Database(tenant_id).switch_schema()
|
||||
else:
|
||||
raise Exception(f'Cannot switch schema for tenant {tenant_id}: user {current_user.email} does not have access')
|
||||
|
||||
|
||||
|
||||
@@ -69,38 +69,38 @@
|
||||
<ul class="navbar-nav navbar-nav-hover mx-auto">
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ dropdown('Tenant Configuration', 'source_environment', [
|
||||
{'name': 'Tenants', 'url': '/user/select_tenant', 'roles': ['Super User']},
|
||||
{'name': 'Tenant Overview', 'url': '/user/tenant_overview', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Edit Tenant', 'url': '/user/tenant/' ~ session['tenant'].get('id'), 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Tenant Domains', 'url': '/user/view_tenant_domains', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Tenant Projects', 'url': '/user/tenant_projects', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Users', 'url': '/user/view_users', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Tenants', 'url': '/user/select_tenant', 'roles': ['Super User', 'Partner Admin']},
|
||||
{'name': 'Tenant Overview', 'url': '/user/tenant_overview', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Edit Tenant', 'url': '/user/tenant/' ~ session['tenant'].get('id'), 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Tenant Domains', 'url': '/user/view_tenant_domains', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Tenant Projects', 'url': '/user/tenant_projects', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Users', 'url': '/user/view_users', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
]) }}
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ dropdown('Document Mgmt', 'note_stack', [
|
||||
{'name': 'Catalogs', 'url': '/document/catalogs', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Processors', 'url': '/document/processors', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Retrievers', 'url': '/document/retrievers', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Add Document', 'url': '/document/add_document', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Add URL', 'url': '/document/add_url', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Documents', 'url': '/document/documents', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Document Versions', 'url': '/document/document_versions_list', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Library Operations', 'url': '/document/library_operations', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Catalogs', 'url': '/document/catalogs', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Processors', 'url': '/document/processors', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Retrievers', 'url': '/document/retrievers', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Add Document', 'url': '/document/add_document', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Add URL', 'url': '/document/add_url', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Documents', 'url': '/document/documents', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Document Versions', 'url': '/document/document_versions_list', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Library Operations', 'url': '/document/library_operations', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
]) }}
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ dropdown('Interactions', 'hub', [
|
||||
{'name': 'Specialists', 'url': '/interaction/specialists', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Chat Sessions', 'url': '/interaction/chat_sessions', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Specialists', 'url': '/interaction/specialists', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
{'name': 'Chat Sessions', 'url': '/interaction/chat_sessions', 'roles': ['Super User', 'Partner Admin', 'Tenant Admin']},
|
||||
]) }}
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ dropdown('Administration', 'settings', [
|
||||
{'name': 'License Tiers', 'url': '/entitlements/view_license_tiers', 'roles': ['Super User']},
|
||||
{'name': 'License Tiers', 'url': '/entitlements/view_license_tiers', 'roles': ['Super User', 'Partner Admin']},
|
||||
{'name': 'Trigger Actions', 'url': '/administration/trigger_actions', 'roles': ['Super User']},
|
||||
{'name': 'Licenses', 'url': '/entitlements/view_licenses', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Usage', 'url': '/entitlements/view_usages', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Licenses', 'url': '/entitlements/view_licenses', 'roles': ['Super User', 'Tenant Admin', 'Partner Admin']},
|
||||
{'name': 'Usage', 'url': '/entitlements/view_usages', 'roles': ['Super User', 'Tenant Admin', 'Partner Admin']},
|
||||
{'name': 'Partners', 'url': '/administration/partners', 'roles': ['Super User']},
|
||||
{'name': 'Partner Services', 'url': '/administration/partner_services', 'roles': ['Super User']},
|
||||
]) }}
|
||||
@@ -125,7 +125,7 @@
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% if current_user.has_roles('Super User') and 'partner' in session %}
|
||||
{% if 'partner' in session %}
|
||||
<li class="nav-item mt-2">
|
||||
<a href="/session_defaults" class="btn btn-sm bg-gradient-success mb-0">
|
||||
PARTNER {{ session['partner'].get('id', 'None') }}: {{ session['partner'].get('name', 'None') }}
|
||||
|
||||
@@ -37,7 +37,7 @@ def confirm_email_fail():
|
||||
|
||||
|
||||
@basic_bp.route('/session_defaults', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def session_defaults():
|
||||
try:
|
||||
# Get tenant session
|
||||
|
||||
@@ -53,7 +53,7 @@ def before_request():
|
||||
|
||||
|
||||
@document_bp.route('/catalog', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def catalog():
|
||||
form = CatalogForm()
|
||||
|
||||
@@ -80,7 +80,7 @@ def catalog():
|
||||
|
||||
|
||||
@document_bp.route('/catalogs', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def catalogs():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
@@ -98,7 +98,7 @@ def catalogs():
|
||||
|
||||
|
||||
@document_bp.route('/handle_catalog_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_catalog_selection():
|
||||
action = request.form['action']
|
||||
if action == 'create_catalog':
|
||||
@@ -119,7 +119,7 @@ def handle_catalog_selection():
|
||||
|
||||
|
||||
@document_bp.route('/catalog/<int:catalog_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_catalog(catalog_id):
|
||||
catalog = Catalog.query.get_or_404(catalog_id)
|
||||
tenant_id = session.get('tenant').get('id')
|
||||
@@ -150,7 +150,7 @@ def edit_catalog(catalog_id):
|
||||
|
||||
|
||||
@document_bp.route('/processor', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def processor():
|
||||
form = ProcessorForm()
|
||||
|
||||
@@ -179,7 +179,7 @@ def processor():
|
||||
|
||||
|
||||
@document_bp.route('/processor/<int:processor_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_processor(processor_id):
|
||||
"""Edit an existing processorr configuration."""
|
||||
# Get the processor or return 404
|
||||
@@ -228,7 +228,7 @@ def edit_processor(processor_id):
|
||||
|
||||
|
||||
@document_bp.route('/processors', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def processors():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
@@ -247,7 +247,7 @@ def processors():
|
||||
|
||||
|
||||
@document_bp.route('/handle_processor_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_processor_selection():
|
||||
action = request.form['action']
|
||||
if action == 'create_processor':
|
||||
@@ -262,7 +262,7 @@ def handle_processor_selection():
|
||||
|
||||
|
||||
@document_bp.route('/retriever', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def retriever():
|
||||
form = RetrieverForm()
|
||||
|
||||
@@ -271,6 +271,8 @@ def retriever():
|
||||
new_retriever = Retriever()
|
||||
form.populate_obj(new_retriever)
|
||||
new_retriever.catalog_id = form.catalog.data.id
|
||||
new_retriever.type_version = cache_manager.retrievers_version_tree_cache.get_latest_version(
|
||||
new_retriever.type)
|
||||
|
||||
set_logging_information(new_retriever, dt.now(tz.utc))
|
||||
|
||||
@@ -291,7 +293,7 @@ def retriever():
|
||||
|
||||
|
||||
@document_bp.route('/retriever/<int:retriever_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_retriever(retriever_id):
|
||||
"""Edit an existing retriever configuration."""
|
||||
# Get the retriever or return 404
|
||||
@@ -341,7 +343,7 @@ def edit_retriever(retriever_id):
|
||||
|
||||
|
||||
@document_bp.route('/retrievers', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def retrievers():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
@@ -360,7 +362,7 @@ def retrievers():
|
||||
|
||||
|
||||
@document_bp.route('/handle_retriever_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_retriever_selection():
|
||||
action = request.form['action']
|
||||
if action == 'create_retriever':
|
||||
@@ -375,7 +377,7 @@ def handle_retriever_selection():
|
||||
|
||||
|
||||
@document_bp.route('/add_document', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def add_document():
|
||||
form = AddDocumentForm(request.form)
|
||||
catalog_id = session.get('catalog_id', None)
|
||||
@@ -430,7 +432,7 @@ def add_document():
|
||||
|
||||
|
||||
@document_bp.route('/add_url', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def add_url():
|
||||
form = AddURLForm(request.form)
|
||||
catalog_id = session.get('catalog_id', None)
|
||||
@@ -489,14 +491,14 @@ def add_url():
|
||||
|
||||
|
||||
@document_bp.route('/documents', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def documents():
|
||||
view = DocumentListView(Document, 'document/documents.html', per_page=10)
|
||||
return view.get()
|
||||
|
||||
|
||||
@document_bp.route('/handle_document_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_document_selection():
|
||||
document_identification = request.form['selected_row']
|
||||
if isinstance(document_identification, int) or document_identification.isdigit():
|
||||
@@ -527,7 +529,7 @@ def handle_document_selection():
|
||||
|
||||
|
||||
@document_bp.route('/edit_document/<int:document_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_document_view(document_id):
|
||||
# Use an alias for the Catalog to avoid column name conflicts
|
||||
CatalogAlias = aliased(Catalog)
|
||||
@@ -568,7 +570,7 @@ def edit_document_view(document_id):
|
||||
|
||||
|
||||
@document_bp.route('/edit_document_version/<int:document_version_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_document_version_view(document_version_id):
|
||||
doc_vers = DocumentVersion.query.get_or_404(document_version_id)
|
||||
form = EditDocumentVersionForm(request.form, obj=doc_vers)
|
||||
@@ -607,7 +609,7 @@ def edit_document_version_view(document_version_id):
|
||||
|
||||
|
||||
@document_bp.route('/document_versions/<int:document_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def document_versions(document_id):
|
||||
doc = Document.query.get_or_404(document_id)
|
||||
doc_desc = f'Document {doc.name}'
|
||||
@@ -631,7 +633,7 @@ def document_versions(document_id):
|
||||
|
||||
|
||||
@document_bp.route('/handle_document_version_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_document_version_selection():
|
||||
document_version_identification = request.form['selected_row']
|
||||
if isinstance(document_version_identification, int) or document_version_identification.isdigit():
|
||||
@@ -658,13 +660,13 @@ def handle_document_version_selection():
|
||||
|
||||
|
||||
@document_bp.route('/library_operations', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def library_operations():
|
||||
return render_template('document/library_operations.html')
|
||||
|
||||
|
||||
@document_bp.route('/handle_library_selection', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_library_selection():
|
||||
action = request.form['action']
|
||||
|
||||
@@ -762,7 +764,7 @@ def create_default_rag_library():
|
||||
|
||||
|
||||
@document_bp.route('/document_versions_list', methods=['GET'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def document_versions_list():
|
||||
view = DocumentVersionListView(DocumentVersion, 'document/document_versions_list_view.html', per_page=20)
|
||||
return view.get()
|
||||
|
||||
@@ -45,7 +45,7 @@ def license_tier():
|
||||
|
||||
|
||||
@entitlements_bp.route('/view_license_tiers', methods=['GET', 'POST'])
|
||||
@roles_required('Super User')
|
||||
@roles_accepted('Super User')
|
||||
def view_license_tiers():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
@@ -68,7 +68,7 @@ def view_license_tiers():
|
||||
|
||||
|
||||
@entitlements_bp.route('/handle_license_tier_selection', methods=['POST'])
|
||||
@roles_required('Super User')
|
||||
@roles_accepted('Super User')
|
||||
def handle_license_tier_selection():
|
||||
action = request.form['action']
|
||||
if action == 'create_license_tier':
|
||||
@@ -214,7 +214,7 @@ def edit_license(license_id):
|
||||
|
||||
|
||||
@entitlements_bp.route('/view_usages')
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def view_usages():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
@@ -236,7 +236,7 @@ def view_usages():
|
||||
|
||||
|
||||
@entitlements_bp.route('/handle_usage_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_usage_selection():
|
||||
usage_identification = request.form['selected_row']
|
||||
usage_id = ast.literal_eval(usage_identification).get('value')
|
||||
@@ -248,7 +248,7 @@ def handle_usage_selection():
|
||||
|
||||
|
||||
@entitlements_bp.route('/view_licenses')
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def view_licenses():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
@@ -285,7 +285,7 @@ def view_licenses():
|
||||
|
||||
|
||||
@entitlements_bp.route('/handle_license_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_license_selection():
|
||||
license_identification = request.form['selected_row']
|
||||
license_id = ast.literal_eval(license_identification).get('value')
|
||||
|
||||
@@ -66,7 +66,7 @@ def chat_sessions():
|
||||
|
||||
|
||||
@interaction_bp.route('/handle_chat_session_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_chat_session_selection():
|
||||
chat_session_identification = request.form['selected_row']
|
||||
cs_id = ast.literal_eval(chat_session_identification).get('value')
|
||||
@@ -82,7 +82,7 @@ def handle_chat_session_selection():
|
||||
|
||||
|
||||
@interaction_bp.route('/view_chat_session/<int:chat_session_id>', methods=['GET'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def view_chat_session(chat_session_id):
|
||||
# Get chat session with user info
|
||||
chat_session = ChatSession.query.get_or_404(chat_session_id)
|
||||
@@ -122,7 +122,7 @@ def view_chat_session(chat_session_id):
|
||||
|
||||
|
||||
@interaction_bp.route('/view_chat_session_by_session_id/<session_id>', methods=['GET'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def view_chat_session_by_session_id(session_id):
|
||||
chat_session = ChatSession.query.filter_by(session_id=session_id).first_or_404()
|
||||
show_chat_session(chat_session)
|
||||
@@ -135,7 +135,7 @@ def show_chat_session(chat_session):
|
||||
|
||||
# Routes for Specialist Management ----------------------------------------------------------------
|
||||
@interaction_bp.route('/specialist', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def specialist():
|
||||
form = SpecialistForm()
|
||||
|
||||
@@ -185,7 +185,7 @@ def specialist():
|
||||
|
||||
|
||||
@interaction_bp.route('/specialist/<int:specialist_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_specialist(specialist_id):
|
||||
specialist = Specialist.query.get_or_404(specialist_id)
|
||||
form = EditSpecialistForm(request.form, obj=specialist)
|
||||
@@ -273,7 +273,7 @@ def edit_specialist(specialist_id):
|
||||
|
||||
|
||||
@interaction_bp.route('/specialists', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def specialists():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
@@ -292,7 +292,7 @@ def specialists():
|
||||
|
||||
|
||||
@interaction_bp.route('/handle_specialist_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_specialist_selection():
|
||||
action = request.form.get('action')
|
||||
if action == 'create_specialist':
|
||||
@@ -309,7 +309,7 @@ def handle_specialist_selection():
|
||||
|
||||
# Routes for Agent management ---------------------------------------------------------------------
|
||||
@interaction_bp.route('/agent/<int:agent_id>/edit', methods=['GET'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_agent(agent_id):
|
||||
agent = EveAIAgent.query.get_or_404(agent_id)
|
||||
form = EditEveAIAgentForm(obj=agent)
|
||||
@@ -325,7 +325,7 @@ def edit_agent(agent_id):
|
||||
|
||||
|
||||
@interaction_bp.route('/agent/<int:agent_id>/save', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def save_agent(agent_id):
|
||||
agent = EveAIAgent.query.get_or_404(agent_id) if agent_id else EveAIAgent()
|
||||
tenant_id = session.get('tenant').get('id')
|
||||
@@ -349,7 +349,7 @@ def save_agent(agent_id):
|
||||
|
||||
# Routes for Task management ----------------------------------------------------------------------
|
||||
@interaction_bp.route('/task/<int:task_id>/edit', methods=['GET'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_task(task_id):
|
||||
task = EveAITask.query.get_or_404(task_id)
|
||||
form = EditEveAITaskForm(obj=task)
|
||||
@@ -361,7 +361,7 @@ def edit_task(task_id):
|
||||
|
||||
|
||||
@interaction_bp.route('/task/<int:task_id>/save', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def save_task(task_id):
|
||||
task = EveAITask.query.get_or_404(task_id) if task_id else EveAITask()
|
||||
tenant_id = session.get('tenant').get('id')
|
||||
@@ -385,7 +385,7 @@ def save_task(task_id):
|
||||
|
||||
# Routes for Tool management ----------------------------------------------------------------------
|
||||
@interaction_bp.route('/tool/<int:tool_id>/edit', methods=['GET'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_tool(tool_id):
|
||||
tool = EveAITool.query.get_or_404(tool_id)
|
||||
form = EditEveAIToolForm(obj=tool)
|
||||
@@ -397,7 +397,7 @@ def edit_tool(tool_id):
|
||||
|
||||
|
||||
@interaction_bp.route('/tool/<int:tool_id>/save', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def save_tool(tool_id):
|
||||
tool = EveAITool.query.get_or_404(tool_id) if tool_id else EveAITool()
|
||||
tenant_id = session.get('tenant').get('id')
|
||||
@@ -421,7 +421,7 @@ def save_tool(tool_id):
|
||||
|
||||
# Component selection handlers --------------------------------------------------------------------
|
||||
@interaction_bp.route('/handle_agent_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_agent_selection():
|
||||
agent_identification = request.form['selected_row']
|
||||
agent_id = ast.literal_eval(agent_identification).get('value')
|
||||
@@ -434,7 +434,7 @@ def handle_agent_selection():
|
||||
|
||||
|
||||
@interaction_bp.route('/handle_task_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_task_selection():
|
||||
task_identification = request.form['selected_row']
|
||||
task_id = ast.literal_eval(task_identification).get('value')
|
||||
@@ -447,7 +447,7 @@ def handle_task_selection():
|
||||
|
||||
|
||||
@interaction_bp.route('/handle_tool_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_tool_selection():
|
||||
tool_identification = request.form['selected_row']
|
||||
tool_id = ast.literal_eval(tool_identification).get('value')
|
||||
@@ -461,7 +461,7 @@ def handle_tool_selection():
|
||||
|
||||
# Routes for Asset management ---------------------------------------------------------------------
|
||||
@interaction_bp.route('/add_asset', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def add_asset():
|
||||
form = AddEveAIAssetForm(request.form)
|
||||
tenant_id = session.get('tenant').get('id')
|
||||
@@ -489,7 +489,7 @@ def add_asset():
|
||||
|
||||
|
||||
@interaction_bp.route('/edit_asset_version/<int:asset_version_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_asset_version(asset_version_id):
|
||||
asset_version = EveAIAssetVersion.query.get_or_404(asset_version_id)
|
||||
form = EditEveAIAssetVersionForm(asset_version)
|
||||
|
||||
@@ -11,7 +11,7 @@ from itsdangerous import URLSafeTimedSerializer
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from common.models.user import User
|
||||
from common.utils.eveai_exceptions import EveAIException
|
||||
from common.utils.eveai_exceptions import EveAIException, EveAINoActiveLicense
|
||||
from common.utils.nginx_utils import prefixed_url_for
|
||||
from eveai_app.views.security_forms import SetPasswordForm, ResetPasswordForm, RequestResetForm
|
||||
from common.extensions import db
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from flask import current_app
|
||||
from flask import current_app, session
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import (StringField, PasswordField, BooleanField, SubmitField, EmailField, IntegerField, DateField,
|
||||
SelectField, SelectMultipleField, FieldList, FormField, FloatField, TextAreaField)
|
||||
from wtforms.validators import DataRequired, Length, Email, NumberRange, Optional, ValidationError
|
||||
import pytz
|
||||
from flask_security import current_user
|
||||
|
||||
from common.models.user import Role
|
||||
from common.services.user_service import UserService
|
||||
@@ -24,6 +25,9 @@ class TenantForm(FlaskForm):
|
||||
timezone = SelectField('Timezone', choices=[], validators=[DataRequired()])
|
||||
# LLM fields
|
||||
llm_model = SelectField('Large Language Model', choices=[], validators=[DataRequired()])
|
||||
|
||||
# For Super Users only - Allow to assign the tenant to the partner
|
||||
assign_to_partner = BooleanField('Assign to Partner', default=False)
|
||||
# Embedding variables
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
@@ -40,6 +44,9 @@ class TenantForm(FlaskForm):
|
||||
self.llm_model.choices = [(model, model) for model in current_app.config['SUPPORTED_LLMS']]
|
||||
# Initialize fallback algorithms
|
||||
self.type.choices = [(t, t) for t in current_app.config['TENANT_TYPES']]
|
||||
# Show field only for Super Users with partner in session
|
||||
if not current_user.has_roles('Super User') or 'partner' not in session:
|
||||
self._fields.pop('assign_to_partner', None)
|
||||
|
||||
|
||||
class BaseUserForm(FlaskForm):
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
# from . import user_bp
|
||||
import uuid
|
||||
from datetime import datetime as dt, timezone as tz
|
||||
from flask import request, redirect, flash, render_template, Blueprint, session, current_app, jsonify
|
||||
from flask import request, redirect, flash, render_template, Blueprint, session, current_app
|
||||
from flask_mailman import EmailMessage
|
||||
from flask_security import hash_password, roles_required, roles_accepted, current_user
|
||||
from itsdangerous import URLSafeTimedSerializer
|
||||
from flask_security import roles_accepted, current_user
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
import ast
|
||||
|
||||
from common.models.user import User, Tenant, Role, TenantDomain, TenantProject, Partner
|
||||
from common.models.user import User, Tenant, Role, TenantDomain, TenantProject, PartnerTenant
|
||||
from common.extensions import db, security, minio_client, simple_encryption
|
||||
from common.services.user_service import UserService
|
||||
from common.utils.security_utils import send_confirmation_email, send_reset_email
|
||||
@@ -19,8 +17,9 @@ from common.utils.database import Database
|
||||
from common.utils.view_assistants import prepare_table_for_macro, form_validation_failed
|
||||
from common.utils.simple_encryption import generate_api_key
|
||||
from common.utils.nginx_utils import prefixed_url_for
|
||||
from common.utils.eveai_exceptions import EveAIDoublePartner, EveAIException
|
||||
from common.utils.eveai_exceptions import EveAIException
|
||||
from common.utils.document_utils import set_logging_information, update_logging_information
|
||||
from common.services.tenant_service import TenantService
|
||||
|
||||
user_bp = Blueprint('user_bp', __name__, url_prefix='/user')
|
||||
|
||||
@@ -36,7 +35,7 @@ def log_after_request(response):
|
||||
|
||||
|
||||
@user_bp.route('/tenant', methods=['GET', 'POST'])
|
||||
@roles_required('Super User')
|
||||
@roles_accepted('Super User', 'Partner Admin')
|
||||
def tenant():
|
||||
form = TenantForm()
|
||||
if request.method == 'GET':
|
||||
@@ -48,7 +47,6 @@ def tenant():
|
||||
new_tenant = Tenant()
|
||||
form.populate_obj(new_tenant)
|
||||
|
||||
# Handle Timestamps
|
||||
timestamp = dt.now(tz.utc)
|
||||
new_tenant.created_at = timestamp
|
||||
new_tenant.updated_at = timestamp
|
||||
@@ -57,11 +55,24 @@ def tenant():
|
||||
try:
|
||||
db.session.add(new_tenant)
|
||||
db.session.commit()
|
||||
|
||||
if current_user.has_roles('Partner Admin') and 'partner' in session:
|
||||
# Always associate with the partner for Partner Admins
|
||||
TenantService.associate_tenant_with_partner(new_tenant.id)
|
||||
elif current_user.has_roles('Super User') and form.assign_to_partner.data and 'partner' in session:
|
||||
# Super User chose to associate with partner
|
||||
TenantService.associate_tenant_with_partner(new_tenant.id)
|
||||
|
||||
except SQLAlchemyError as e:
|
||||
current_app.logger.error(f'Failed to add tenant to database. Error: {str(e)}')
|
||||
flash(f'Failed to add tenant to database. Error: {str(e)}', 'danger')
|
||||
return render_template('user/tenant.html', form=form)
|
||||
|
||||
except EveAIException as e:
|
||||
current_app.logger.error(f'Error associating Tenant {new_tenant.id} to Partner. Error: {str(e)}')
|
||||
flash(f'Error associating Tenant to Partner. Error: {str(e)}', 'danger')
|
||||
return render_template('user/tenant.html', form=form)
|
||||
|
||||
current_app.logger.info(f"Successfully created tenant {new_tenant.id} in Database")
|
||||
flash(f"Successfully created tenant {new_tenant.id} in Database", 'success')
|
||||
|
||||
@@ -81,15 +92,11 @@ def tenant():
|
||||
|
||||
|
||||
@user_bp.route('/tenant/<int:tenant_id>', methods=['GET', 'POST'])
|
||||
@roles_required('Super User')
|
||||
@roles_accepted('Super User', 'Partner Admin')
|
||||
def edit_tenant(tenant_id):
|
||||
tenant = Tenant.query.get_or_404(tenant_id) # This will return a 404 if no tenant is found
|
||||
form = TenantForm(obj=tenant)
|
||||
|
||||
if request.method == 'GET':
|
||||
# Populate the form with tenant data
|
||||
form.populate_obj(tenant)
|
||||
|
||||
if form.validate_on_submit():
|
||||
# Populate the tenant with form data
|
||||
form.populate_obj(tenant)
|
||||
@@ -109,6 +116,7 @@ def edit_tenant(tenant_id):
|
||||
@user_bp.route('/user', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin', 'Partner Admin')
|
||||
def user():
|
||||
tenant_id = session.get('tenant').get('id')
|
||||
form = CreateUserForm()
|
||||
form.tenant_id.data = session.get('tenant').get('id') # It is only possible to create users for the session tenant
|
||||
if form.validate_on_submit():
|
||||
@@ -205,14 +213,40 @@ def edit_user(user_id):
|
||||
|
||||
|
||||
@user_bp.route('/select_tenant', methods=['GET', 'POST'])
|
||||
@roles_required('Super User')
|
||||
@roles_accepted('Super User', 'Partner Admin') # Allow both roles
|
||||
def select_tenant():
|
||||
filter_form = TenantSelectionForm(request.form)
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
|
||||
# Start with a base query
|
||||
query = Tenant.query
|
||||
|
||||
# Apply different filters based on user role
|
||||
if current_user.has_roles('Partner Admin') and 'partner' in session:
|
||||
# Get the partner's management service
|
||||
management_service = next((service for service in session['partner']['services']
|
||||
if service.get('type') == 'MANAGEMENT_SERVICE'), None)
|
||||
|
||||
if management_service:
|
||||
# Get the partner's own tenant
|
||||
partner_tenant_id = session['partner']['tenant_id']
|
||||
|
||||
# Get tenants managed by this partner through PartnerTenant relationships
|
||||
managed_tenant_ids = db.session.query(PartnerTenant.tenant_id).filter_by(
|
||||
partner_service_id=management_service['id']
|
||||
).all()
|
||||
|
||||
# Convert list of tuples to flat list
|
||||
managed_tenant_ids = [tenant_id for (tenant_id,) in managed_tenant_ids]
|
||||
|
||||
# Include partner's own tenant in the list
|
||||
allowed_tenant_ids = [partner_tenant_id] + managed_tenant_ids
|
||||
|
||||
# Filter query to only show allowed tenants
|
||||
query = query.filter(Tenant.id.in_(allowed_tenant_ids))
|
||||
|
||||
# Apply form filters (for both Super User and Partner Admin)
|
||||
if filter_form.validate_on_submit():
|
||||
if filter_form.types.data:
|
||||
query = query.filter(Tenant.type.in_(filter_form.types.data))
|
||||
@@ -220,6 +254,7 @@ def select_tenant():
|
||||
search = f"%{filter_form.search.data}%"
|
||||
query = query.filter(Tenant.name.ilike(search))
|
||||
|
||||
# Finalize query
|
||||
query = query.order_by(Tenant.name)
|
||||
pagination = query.paginate(page=page, per_page=per_page, error_out=False)
|
||||
tenants = pagination.items
|
||||
@@ -230,7 +265,7 @@ def select_tenant():
|
||||
|
||||
|
||||
@user_bp.route('/handle_tenant_selection', methods=['POST'])
|
||||
@roles_required('Super User')
|
||||
@roles_accepted('Super User', 'Partner Admin')
|
||||
def handle_tenant_selection():
|
||||
action = request.form['action']
|
||||
if action == 'create_tenant':
|
||||
@@ -238,6 +273,10 @@ def handle_tenant_selection():
|
||||
|
||||
tenant_identification = request.form['selected_row']
|
||||
tenant_id = ast.literal_eval(tenant_identification).get('value')
|
||||
if not TenantService.can_user_edit_tenant(tenant_id):
|
||||
current_app.logger.info(f"User not authenticated to edit tenant {tenant_id}.")
|
||||
flash(f"You are not authenticated to manage tenant {tenant_id}", 'danger')
|
||||
return redirect(prefixed_url_for('select_tenant'))
|
||||
the_tenant = Tenant.query.get(tenant_id)
|
||||
|
||||
# set tenant information in the session
|
||||
@@ -259,7 +298,7 @@ def handle_tenant_selection():
|
||||
|
||||
|
||||
@user_bp.route('/view_users')
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def view_users():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
@@ -279,7 +318,7 @@ def view_users():
|
||||
|
||||
|
||||
@user_bp.route('/handle_user_action', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_user_action():
|
||||
action = request.form['action']
|
||||
if action == 'create_user':
|
||||
@@ -305,7 +344,7 @@ def handle_user_action():
|
||||
|
||||
|
||||
@user_bp.route('/view_tenant_domains')
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def view_tenant_domains():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
@@ -324,7 +363,7 @@ def view_tenant_domains():
|
||||
|
||||
|
||||
@user_bp.route('/handle_tenant_domain_action', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_tenant_domain_action():
|
||||
action = request.form['action']
|
||||
if action == 'create_tenant_domain':
|
||||
@@ -340,7 +379,7 @@ def handle_tenant_domain_action():
|
||||
|
||||
|
||||
@user_bp.route('/tenant_domain', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def tenant_domain():
|
||||
form = TenantDomainForm()
|
||||
if form.validate_on_submit():
|
||||
@@ -354,7 +393,8 @@ def tenant_domain():
|
||||
db.session.add(new_tenant_domain)
|
||||
db.session.commit()
|
||||
flash('Tenant Domain added successfully.', 'success')
|
||||
current_app.logger.info(f'Tenant Domain {new_tenant_domain.domain} added for tenant {session["tenant"]["id"]}')
|
||||
current_app.logger.info(
|
||||
f'Tenant Domain {new_tenant_domain.domain} added for tenant {session["tenant"]["id"]}')
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback()
|
||||
flash(f'Failed to add Tenant Domain. Error: {str(e)}', 'danger')
|
||||
@@ -368,7 +408,7 @@ def tenant_domain():
|
||||
|
||||
|
||||
@user_bp.route('/tenant_domain/<int:tenant_domain_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_tenant_domain(tenant_domain_id):
|
||||
tenant_domain = TenantDomain.query.get_or_404(tenant_domain_id) # This will return a 404 if no user is found
|
||||
form = TenantDomainForm(obj=tenant_domain)
|
||||
@@ -396,7 +436,7 @@ def edit_tenant_domain(tenant_domain_id):
|
||||
|
||||
|
||||
@user_bp.route('/tenant_overview', methods=['GET'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def tenant_overview():
|
||||
tenant_id = session['tenant']['id']
|
||||
tenant = Tenant.query.get_or_404(tenant_id)
|
||||
@@ -405,7 +445,7 @@ def tenant_overview():
|
||||
|
||||
|
||||
@user_bp.route('/tenant_project', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def tenant_project():
|
||||
form = TenantProjectForm()
|
||||
if request.method == 'GET':
|
||||
@@ -458,7 +498,7 @@ def tenant_project():
|
||||
|
||||
|
||||
@user_bp.route('/tenant_projects', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def tenant_projects():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
@@ -478,7 +518,7 @@ def tenant_projects():
|
||||
|
||||
|
||||
@user_bp.route('/handle_tenant_project_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def handle_tenant_project_selection():
|
||||
action = request.form.get('action')
|
||||
if action == 'create_tenant_project':
|
||||
@@ -508,8 +548,8 @@ def handle_tenant_project_selection():
|
||||
return redirect(prefixed_url_for('user_bp.tenant_projects'))
|
||||
|
||||
|
||||
@user_bp.route('/tenant_project/<int:tenant_project_id>', methods=['GET','POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@user_bp.route('/tenant_project/<int:tenant_project_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def edit_tenant_project(tenant_project_id):
|
||||
tenant_project = TenantProject.query.get_or_404(tenant_project_id)
|
||||
tenant_id = session['tenant']['id']
|
||||
@@ -535,7 +575,7 @@ def edit_tenant_project(tenant_project_id):
|
||||
|
||||
|
||||
@user_bp.route('/tenant_project/delete/<int:tenant_project_id>', methods=['GET', 'POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
@roles_accepted('Super User', 'Partner Admin', 'Tenant Admin')
|
||||
def delete_tenant_project(tenant_project_id):
|
||||
tenant_id = session['tenant']['id']
|
||||
tenant_project = TenantProject.query.get_or_404(tenant_project_id)
|
||||
@@ -570,18 +610,6 @@ def reset_uniquifier(user):
|
||||
send_reset_email(user)
|
||||
|
||||
|
||||
def set_logging_information(obj, timestamp):
|
||||
obj.created_at = timestamp
|
||||
obj.updated_at = timestamp
|
||||
obj.created_by = current_user.id
|
||||
obj.updated_by = current_user.id
|
||||
|
||||
|
||||
def update_logging_information(obj, timestamp):
|
||||
obj.updated_at = timestamp
|
||||
obj.updated_by = current_user.id
|
||||
|
||||
|
||||
def get_notification_email(tenant_id, user_email=None):
|
||||
"""
|
||||
Determine which email address to use for notification.
|
||||
|
||||
Reference in New Issue
Block a user