- Corrections to tenant, catalog, and tenant_make
- Clean-up of tenant elements - ensure the chat_client get's it's initial call rifht.
This commit is contained in:
@@ -45,6 +45,21 @@ class Specialist(db.Model):
|
|||||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
|
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
|
||||||
updated_by = db.Column(db.Integer, db.ForeignKey(User.id))
|
updated_by = db.Column(db.Integer, db.ForeignKey(User.id))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<Specialist {self.id}: {self.name}>"
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
'id': self.id,
|
||||||
|
'name': self.name,
|
||||||
|
'description': self.description,
|
||||||
|
'type': self.type,
|
||||||
|
'type_version': self.type_version,
|
||||||
|
'configuration': self.configuration,
|
||||||
|
'arguments': self.arguments,
|
||||||
|
'active': self.active,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class EveAIAsset(db.Model):
|
class EveAIAsset(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
@@ -238,3 +253,14 @@ class SpecialistMagicLink(db.Model):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<SpecialistMagicLink {self.specialist_id} {self.magic_link_code}>"
|
return f"<SpecialistMagicLink {self.specialist_id} {self.magic_link_code}>"
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
'id': self.id,
|
||||||
|
'name': self.name,
|
||||||
|
'description': self.description,
|
||||||
|
'magic_link_code': self.magic_link_code,
|
||||||
|
'valid_from': self.valid_from,
|
||||||
|
'valid_to': self.valid_to,
|
||||||
|
'specialist_args': self.specialist_args,
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ class Tenant(db.Model):
|
|||||||
|
|
||||||
# language information
|
# language information
|
||||||
default_language = db.Column(db.String(2), nullable=True)
|
default_language = db.Column(db.String(2), nullable=True)
|
||||||
allowed_languages = db.Column(ARRAY(sa.String(2)), nullable=True)
|
|
||||||
|
|
||||||
# Entitlements
|
# Entitlements
|
||||||
currency = db.Column(db.String(20), nullable=True)
|
currency = db.Column(db.String(20), nullable=True)
|
||||||
@@ -63,7 +62,6 @@ class Tenant(db.Model):
|
|||||||
'timezone': self.timezone,
|
'timezone': self.timezone,
|
||||||
'type': self.type,
|
'type': self.type,
|
||||||
'default_language': self.default_language,
|
'default_language': self.default_language,
|
||||||
'allowed_languages': self.allowed_languages,
|
|
||||||
'currency': self.currency,
|
'currency': self.currency,
|
||||||
'default_tenant_make_id': self.default_tenant_make_id,
|
'default_tenant_make_id': self.default_tenant_make_id,
|
||||||
}
|
}
|
||||||
@@ -198,6 +196,20 @@ class TenantMake(db.Model):
|
|||||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
|
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
|
||||||
updated_by = db.Column(db.Integer, db.ForeignKey('public.user.id'))
|
updated_by = db.Column(db.Integer, db.ForeignKey('public.user.id'))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<TenantMake {self.id} for tenant {self.tenant_id}: {self.name}>"
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
'id': self.id,
|
||||||
|
'name': self.name,
|
||||||
|
'description': self.description,
|
||||||
|
'active': self.active,
|
||||||
|
'website': self.website,
|
||||||
|
'logo_url': self.logo_url,
|
||||||
|
'chat_customisation_options': self.chat_customisation_options,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Partner(db.Model):
|
class Partner(db.Model):
|
||||||
__bind_key__ = 'public'
|
__bind_key__ = 'public'
|
||||||
|
|||||||
@@ -220,3 +220,17 @@ class SpecialistServices:
|
|||||||
db.session.add(tool)
|
db.session.add(tool)
|
||||||
current_app.logger.info(f"Created tool {tool.id} of type {tool_type}")
|
current_app.logger.info(f"Created tool {tool.id} of type {tool_type}")
|
||||||
return tool
|
return tool
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_specialist_system_field(specialist_id, config_name, system_name):
|
||||||
|
specialist = Specialist.query.get(specialist_id)
|
||||||
|
if not specialist:
|
||||||
|
raise ValueError(f"Specialist with ID {specialist_id} not found")
|
||||||
|
config = cache_manager.specialists_config_cache.get_config(specialist.type, specialist.version)
|
||||||
|
if not config:
|
||||||
|
raise ValueError(f"No configuration found for {specialist.type} version {specialist.version}")
|
||||||
|
potential_field = config.get(config_name, None)
|
||||||
|
if potential_field:
|
||||||
|
if potential_field.type == 'system' and potential_field.system_name == system_name:
|
||||||
|
return specialist.configuration.get(config_name, None)
|
||||||
|
return None
|
||||||
|
|||||||
@@ -5,6 +5,17 @@ All notable changes to EveAI will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [2.3.4-alfa]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Introduction of Tenant Make
|
||||||
|
- Introduction of 'system' type for dynamic attributes
|
||||||
|
- Introduce Tenant Make to Traicie Specialists
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Enable Specialist 'activation' / 'deactivation'
|
||||||
|
- Unique constraints introduced for Catalog Name (tenant level) and make name (public level)
|
||||||
|
|
||||||
## [2.3.3-alfa]
|
## [2.3.3-alfa]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -8,7 +8,19 @@
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro render_field_content(field, disabled=False, readonly=False, class='') %}
|
{% macro render_field_content(field, disabled=False, readonly=False, class='') %}
|
||||||
{% if field.type == 'BooleanField' %}
|
{# Check if this is a hidden input field, if so, render only the field without label #}
|
||||||
|
{{ debug_to_console("Field Class: ", field.widget.__class__.__name__) }}
|
||||||
|
{% if field.widget.__class__.__name__ == 'HiddenInput' %}
|
||||||
|
{{ debug_to_console("Hidden Field: ", "Detected") }}
|
||||||
|
{{ field(class="form-control " + class, disabled=disabled, readonly=readonly) }}
|
||||||
|
{% if field.errors %}
|
||||||
|
<div class="invalid-feedback d-block">
|
||||||
|
{% for error in field.errors %}
|
||||||
|
{{ error }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% elif field.type == 'BooleanField' %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
{{ field(class="form-check-input " + class, disabled=disabled, readonly=readonly, required=False) }}
|
{{ field(class="form-check-input " + class, disabled=disabled, readonly=readonly, required=False) }}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ def validate_catalog_name(form, field):
|
|||||||
|
|
||||||
|
|
||||||
class CatalogForm(FlaskForm):
|
class CatalogForm(FlaskForm):
|
||||||
id = IntegerField('ID', widget=HiddenInput())
|
|
||||||
name = StringField('Name', validators=[DataRequired(), Length(max=50), validate_catalog_name])
|
name = StringField('Name', validators=[DataRequired(), Length(max=50), validate_catalog_name])
|
||||||
description = TextAreaField('Description', validators=[Optional()])
|
description = TextAreaField('Description', validators=[Optional()])
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,6 @@ class SpecialistMagicLinkForm(FlaskForm):
|
|||||||
description = TextAreaField('Description', validators=[Optional()])
|
description = TextAreaField('Description', validators=[Optional()])
|
||||||
magic_link_code = StringField('Magic Link Code', validators=[DataRequired(), Length(max=55)], render_kw={'readonly': True})
|
magic_link_code = StringField('Magic Link Code', validators=[DataRequired(), Length(max=55)], render_kw={'readonly': True})
|
||||||
specialist_id = SelectField('Specialist', validators=[DataRequired()])
|
specialist_id = SelectField('Specialist', validators=[DataRequired()])
|
||||||
tenant_make_id = SelectField('Tenant Make', validators=[Optional()], coerce=int)
|
|
||||||
valid_from = DateField('Valid From', id='form-control datepicker', validators=[Optional()])
|
valid_from = DateField('Valid From', id='form-control datepicker', validators=[Optional()])
|
||||||
valid_to = DateField('Valid To', id='form-control datepicker', validators=[Optional()])
|
valid_to = DateField('Valid To', id='form-control datepicker', validators=[Optional()])
|
||||||
|
|
||||||
@@ -155,10 +154,6 @@ class SpecialistMagicLinkForm(FlaskForm):
|
|||||||
# Dynamically populate the specialist field
|
# Dynamically populate the specialist field
|
||||||
self.specialist_id.choices = [(specialist.id, specialist.name) for specialist in specialists]
|
self.specialist_id.choices = [(specialist.id, specialist.name) for specialist in specialists]
|
||||||
|
|
||||||
# Dynamically populate the tenant_make field with None as first option
|
|
||||||
tenant_makes = TenantMake.query.all()
|
|
||||||
self.tenant_make_id.choices = [(0, 'None')] + [(make.id, make.name) for make in tenant_makes]
|
|
||||||
|
|
||||||
|
|
||||||
class EditSpecialistMagicLinkForm(DynamicFormBase):
|
class EditSpecialistMagicLinkForm(DynamicFormBase):
|
||||||
name = StringField('Name', validators=[DataRequired(), Length(max=50)])
|
name = StringField('Name', validators=[DataRequired(), Length(max=50)])
|
||||||
@@ -168,7 +163,6 @@ class EditSpecialistMagicLinkForm(DynamicFormBase):
|
|||||||
specialist_id = IntegerField('Specialist', validators=[DataRequired()], render_kw={'readonly': True})
|
specialist_id = IntegerField('Specialist', validators=[DataRequired()], render_kw={'readonly': True})
|
||||||
specialist_name = StringField('Specialist Name', validators=[DataRequired()], render_kw={'readonly': True})
|
specialist_name = StringField('Specialist Name', validators=[DataRequired()], render_kw={'readonly': True})
|
||||||
tenant_make_id = SelectField('Tenant Make', validators=[Optional()], coerce=int)
|
tenant_make_id = SelectField('Tenant Make', validators=[Optional()], coerce=int)
|
||||||
tenant_make_name = StringField('Tenant Make Name', validators=[Optional()], render_kw={'readonly': True})
|
|
||||||
valid_from = DateField('Valid From', id='form-control datepicker', validators=[Optional()])
|
valid_from = DateField('Valid From', id='form-control datepicker', validators=[Optional()])
|
||||||
valid_to = DateField('Valid To', id='form-control datepicker', validators=[Optional()])
|
valid_to = DateField('Valid To', id='form-control datepicker', validators=[Optional()])
|
||||||
|
|
||||||
|
|||||||
@@ -705,6 +705,14 @@ def specialist_magic_link():
|
|||||||
new_spec_ml_tenant.magic_link_code = new_specialist_magic_link.magic_link_code
|
new_spec_ml_tenant.magic_link_code = new_specialist_magic_link.magic_link_code
|
||||||
new_spec_ml_tenant.tenant_id = tenant_id
|
new_spec_ml_tenant.tenant_id = tenant_id
|
||||||
|
|
||||||
|
# Define the make valid for this magic link
|
||||||
|
make_id = SpecialistServices.get_specialist_system_field(new_specialist_magic_link.id,
|
||||||
|
"make", "tenant_make")
|
||||||
|
if make_id:
|
||||||
|
new_spec_ml_tenant.tenant_make_id = make_id
|
||||||
|
elif session.get('tenant').get('default_tenant_make_id'):
|
||||||
|
new_spec_ml_tenant.tenant_make_id = session.get('tenant').get('default_tenant_make_id')
|
||||||
|
|
||||||
db.session.add(new_specialist_magic_link)
|
db.session.add(new_specialist_magic_link)
|
||||||
db.session.add(new_spec_ml_tenant)
|
db.session.add(new_spec_ml_tenant)
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,41 @@ class TenantForm(FlaskForm):
|
|||||||
website = StringField('Website', validators=[DataRequired(), Length(max=255)])
|
website = StringField('Website', validators=[DataRequired(), Length(max=255)])
|
||||||
# language fields
|
# language fields
|
||||||
default_language = SelectField('Default Language', choices=[], validators=[DataRequired()])
|
default_language = SelectField('Default Language', choices=[], validators=[DataRequired()])
|
||||||
allowed_languages = SelectMultipleField('Allowed Languages', choices=[], validators=[DataRequired()])
|
# invoicing fields
|
||||||
|
currency = SelectField('Currency', choices=[], validators=[DataRequired()])
|
||||||
|
# Timezone
|
||||||
|
timezone = SelectField('Timezone', 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')
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(TenantForm, self).__init__(*args, **kwargs)
|
||||||
|
# initialise language fields
|
||||||
|
self.default_language.choices = [(lang, lang.lower()) for lang in current_app.config['SUPPORTED_LANGUAGES']]
|
||||||
|
# initialise currency field
|
||||||
|
self.currency.choices = [(curr, curr) for curr in current_app.config['SUPPORTED_CURRENCIES']]
|
||||||
|
# initialise timezone
|
||||||
|
self.timezone.choices = [(tz, tz) for tz in pytz.common_timezones]
|
||||||
|
# Initialize fallback algorithms
|
||||||
|
self.type.choices = [(t, t) for t in current_app.config['TENANT_TYPES']]
|
||||||
|
# Initialize default tenant make choices
|
||||||
|
tenant_id = session.get('tenant', {}).get('id') if 'tenant' in session else None
|
||||||
|
# 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 EditTenantForm(FlaskForm):
|
||||||
|
id = IntegerField('ID', widget=HiddenInput())
|
||||||
|
name = StringField('Name', validators=[DataRequired(), Length(max=80)])
|
||||||
|
code = StringField('Code', validators=[DataRequired()], render_kw={'readonly': True})
|
||||||
|
type = SelectField('Tenant Type', validators=[Optional()], default='Active')
|
||||||
|
website = StringField('Website', validators=[DataRequired(), Length(max=255)])
|
||||||
|
# language fields
|
||||||
|
default_language = SelectField('Default Language', choices=[], validators=[DataRequired()])
|
||||||
# invoicing fields
|
# invoicing fields
|
||||||
currency = SelectField('Currency', choices=[], validators=[DataRequired()])
|
currency = SelectField('Currency', choices=[], validators=[DataRequired()])
|
||||||
# Timezone
|
# Timezone
|
||||||
@@ -34,10 +68,9 @@ class TenantForm(FlaskForm):
|
|||||||
submit = SubmitField('Submit')
|
submit = SubmitField('Submit')
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(TenantForm, self).__init__(*args, **kwargs)
|
super(EditTenantForm, self).__init__(*args, **kwargs)
|
||||||
# initialise language fields
|
# initialise language fields
|
||||||
self.default_language.choices = [(lang, lang.lower()) for lang in current_app.config['SUPPORTED_LANGUAGES']]
|
self.default_language.choices = [(lang, lang.lower()) for lang in current_app.config['SUPPORTED_LANGUAGES']]
|
||||||
self.allowed_languages.choices = [(lang, lang.lower()) for lang in current_app.config['SUPPORTED_LANGUAGES']]
|
|
||||||
# initialise currency field
|
# initialise currency field
|
||||||
self.currency.choices = [(curr, curr) for curr in current_app.config['SUPPORTED_CURRENCIES']]
|
self.currency.choices = [(curr, curr) for curr in current_app.config['SUPPORTED_CURRENCIES']]
|
||||||
# initialise timezone
|
# initialise timezone
|
||||||
@@ -45,7 +78,7 @@ class TenantForm(FlaskForm):
|
|||||||
# Initialize fallback algorithms
|
# Initialize fallback algorithms
|
||||||
self.type.choices = [(t, t) for t in current_app.config['TENANT_TYPES']]
|
self.type.choices = [(t, t) for t in current_app.config['TENANT_TYPES']]
|
||||||
# Initialize default tenant make choices
|
# Initialize default tenant make choices
|
||||||
tenant_id = session.get('tenant', {}).get('id') if 'tenant' in session else None
|
tenant_id = self.id.data
|
||||||
if tenant_id:
|
if tenant_id:
|
||||||
tenant_makes = TenantMake.query.filter_by(tenant_id=tenant_id, active=True).all()
|
tenant_makes = TenantMake.query.filter_by(tenant_id=tenant_id, active=True).all()
|
||||||
self.default_tenant_make_id.choices = [(str(make.id), make.name) for make in tenant_makes]
|
self.default_tenant_make_id.choices = [(str(make.id), make.name) for make in tenant_makes]
|
||||||
@@ -154,6 +187,13 @@ def validate_make_name(form, field):
|
|||||||
|
|
||||||
|
|
||||||
class TenantMakeForm(DynamicFormBase):
|
class TenantMakeForm(DynamicFormBase):
|
||||||
|
name = StringField('Name', validators=[DataRequired(), Length(max=50), validate_make_name])
|
||||||
|
description = TextAreaField('Description', validators=[Optional()])
|
||||||
|
active = BooleanField('Active', validators=[Optional()], default=True)
|
||||||
|
website = StringField('Website', validators=[DataRequired(), Length(max=255)])
|
||||||
|
logo_url = StringField('Logo URL', validators=[Optional(), Length(max=255)])
|
||||||
|
|
||||||
|
class EditTenantMakeForm(DynamicFormBase):
|
||||||
id = IntegerField('ID', widget=HiddenInput())
|
id = IntegerField('ID', widget=HiddenInput())
|
||||||
name = StringField('Name', validators=[DataRequired(), Length(max=50), validate_make_name])
|
name = StringField('Name', validators=[DataRequired(), Length(max=50), validate_make_name])
|
||||||
description = TextAreaField('Description', validators=[Optional()])
|
description = TextAreaField('Description', validators=[Optional()])
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from common.utils.dynamic_field_utils import create_default_config_from_type_con
|
|||||||
from common.utils.security_utils import send_confirmation_email, send_reset_email
|
from common.utils.security_utils import send_confirmation_email, send_reset_email
|
||||||
from config.type_defs.service_types import SERVICE_TYPES
|
from config.type_defs.service_types import SERVICE_TYPES
|
||||||
from .user_forms import TenantForm, CreateUserForm, EditUserForm, TenantDomainForm, TenantSelectionForm, \
|
from .user_forms import TenantForm, CreateUserForm, EditUserForm, TenantDomainForm, TenantSelectionForm, \
|
||||||
TenantProjectForm, EditTenantProjectForm, TenantMakeForm
|
TenantProjectForm, EditTenantProjectForm, TenantMakeForm, EditTenantForm
|
||||||
from common.utils.database import Database
|
from common.utils.database import Database
|
||||||
from common.utils.view_assistants import prepare_table_for_macro, form_validation_failed
|
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.simple_encryption import generate_api_key
|
||||||
@@ -53,10 +53,6 @@ def tenant():
|
|||||||
new_tenant = Tenant()
|
new_tenant = Tenant()
|
||||||
form.populate_obj(new_tenant)
|
form.populate_obj(new_tenant)
|
||||||
|
|
||||||
# Convert default_tenant_make_id to integer if not empty
|
|
||||||
if form.default_tenant_make_id.data:
|
|
||||||
new_tenant.default_tenant_make_id = int(form.default_tenant_make_id.data)
|
|
||||||
|
|
||||||
timestamp = dt.now(tz.utc)
|
timestamp = dt.now(tz.utc)
|
||||||
new_tenant.created_at = timestamp
|
new_tenant.created_at = timestamp
|
||||||
new_tenant.updated_at = timestamp
|
new_tenant.updated_at = timestamp
|
||||||
@@ -116,7 +112,7 @@ def tenant():
|
|||||||
@roles_accepted('Super User', 'Partner Admin')
|
@roles_accepted('Super User', 'Partner Admin')
|
||||||
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 = EditTenantForm(obj=tenant)
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
# Populate the tenant with form data
|
# Populate the tenant with form data
|
||||||
@@ -471,7 +467,7 @@ def edit_tenant_domain(tenant_domain_id):
|
|||||||
def tenant_overview():
|
def tenant_overview():
|
||||||
tenant_id = session['tenant']['id']
|
tenant_id = session['tenant']['id']
|
||||||
tenant = Tenant.query.get_or_404(tenant_id)
|
tenant = Tenant.query.get_or_404(tenant_id)
|
||||||
form = TenantForm(obj=tenant)
|
form = EditTenantForm(obj=tenant)
|
||||||
|
|
||||||
# Zet de waarde van default_tenant_make_id
|
# Zet de waarde van default_tenant_make_id
|
||||||
if tenant.default_tenant_make_id:
|
if tenant.default_tenant_make_id:
|
||||||
@@ -683,7 +679,8 @@ def tenant_makes():
|
|||||||
page = request.args.get('page', 1, type=int)
|
page = request.args.get('page', 1, type=int)
|
||||||
per_page = request.args.get('per_page', 10, type=int)
|
per_page = request.args.get('per_page', 10, type=int)
|
||||||
|
|
||||||
query = TenantMake.query.order_by(TenantMake.id)
|
tenant_id = session['tenant']['id']
|
||||||
|
query = TenantMake.query.filter_by(tenant_id=tenant_id).order_by(TenantMake.id)
|
||||||
|
|
||||||
pagination = query.paginate(page=page, per_page=per_page)
|
pagination = query.paginate(page=page, per_page=per_page)
|
||||||
tenant_makes = pagination.items
|
tenant_makes = pagination.items
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from flask import Flask, jsonify
|
|
||||||
|
from flask import Flask, jsonify, request
|
||||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||||
import logging.config
|
import logging.config
|
||||||
|
|
||||||
@@ -74,6 +75,13 @@ def create_app(config_file=None):
|
|||||||
|
|
||||||
app.logger.info(f"EveAI Chat Client Started Successfully (PID: {os.getpid()})")
|
app.logger.info(f"EveAI Chat Client Started Successfully (PID: {os.getpid()})")
|
||||||
app.logger.info("-------------------------------------------------------------------------------------------------")
|
app.logger.info("-------------------------------------------------------------------------------------------------")
|
||||||
|
|
||||||
|
# @app.before_request
|
||||||
|
# def app_before_request():
|
||||||
|
# app.logger.debug(f'App before request: {request.path} ===== Method: {request.method} =====')
|
||||||
|
# app.logger.debug(f'Full URL: {request.url}')
|
||||||
|
# app.logger.debug(f'Endpoint: {request.endpoint}')
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
<!-- Custom theme colors from tenant settings -->
|
<!-- Custom theme colors from tenant settings -->
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--primary-color: {{ customization.primary_color|default('#007bff') }};
|
--primary-color: {{ customisation.primary_color|default('#007bff') }};
|
||||||
--secondary-color: {{ customization.secondary_color|default('#6c757d') }};
|
--secondary-color: {{ customisation.secondary_color|default('#6c757d') }};
|
||||||
--background-color: {{ customization.background_color|default('#ffffff') }};
|
--background-color: {{ customisation.background_color|default('#ffffff') }};
|
||||||
--text-color: {{ customization.text_color|default('#212529') }};
|
--text-color: {{ customisation.text_color|default('#212529') }};
|
||||||
--sidebar-color: {{ customization.sidebar_color|default('#f8f9fa') }};
|
--sidebar-color: {{ customisation.sidebar_color|default('#f8f9fa') }};
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,32 @@ from flask import Blueprint, render_template, request, session, current_app, jso
|
|||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
|
||||||
from common.extensions import db
|
from common.extensions import db
|
||||||
from common.models.user import Tenant, SpecialistMagicLinkTenant
|
from common.models.user import Tenant, SpecialistMagicLinkTenant, TenantMake
|
||||||
from common.models.interaction import SpecialistMagicLink, Specialist, ChatSession, Interaction
|
from common.models.interaction import SpecialistMagicLink, Specialist, ChatSession, Interaction
|
||||||
from common.services.interaction.specialist_services import SpecialistServices
|
from common.services.interaction.specialist_services import SpecialistServices
|
||||||
from common.utils.database import Database
|
from common.utils.database import Database
|
||||||
from common.utils.chat_utils import get_default_chat_customisation
|
from common.utils.chat_utils import get_default_chat_customisation
|
||||||
|
|
||||||
chat_bp = Blueprint('chat', __name__)
|
chat_bp = Blueprint('chat_bp', __name__, url_prefix='/chat')
|
||||||
|
|
||||||
|
@chat_bp.before_request
|
||||||
|
def log_before_request():
|
||||||
|
current_app.logger.debug(f'Before request: {request.path} =====================================')
|
||||||
|
|
||||||
|
|
||||||
|
@chat_bp.after_request
|
||||||
|
def log_after_request(response):
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
# @chat_bp.before_request
|
||||||
|
# def before_request():
|
||||||
|
# try:
|
||||||
|
# mw_before_request()
|
||||||
|
# except Exception as e:
|
||||||
|
# current_app.logger.error(f'Error switching schema in Document Blueprint: {e}')
|
||||||
|
# raise
|
||||||
|
|
||||||
|
|
||||||
@chat_bp.route('/')
|
@chat_bp.route('/')
|
||||||
def index():
|
def index():
|
||||||
@@ -31,14 +50,12 @@ def chat(magic_link_code):
|
|||||||
current_app.logger.error(f"Invalid magic link code: {magic_link_code}")
|
current_app.logger.error(f"Invalid magic link code: {magic_link_code}")
|
||||||
return render_template('error.html', message="Invalid magic link code.")
|
return render_template('error.html', message="Invalid magic link code.")
|
||||||
|
|
||||||
tenant_id = magic_link_tenant.tenant_id
|
|
||||||
|
|
||||||
# Get tenant information
|
# Get tenant information
|
||||||
|
tenant_id = magic_link_tenant.tenant_id
|
||||||
tenant = Tenant.query.get(tenant_id)
|
tenant = Tenant.query.get(tenant_id)
|
||||||
if not tenant:
|
if not tenant:
|
||||||
current_app.logger.error(f"Tenant not found for ID: {tenant_id}")
|
current_app.logger.error(f"Tenant not found for ID: {tenant_id}")
|
||||||
return render_template('error.html', message="Tenant not found.")
|
return render_template('error.html', message="Tenant not found.")
|
||||||
|
|
||||||
# Switch to tenant schema
|
# Switch to tenant schema
|
||||||
Database(tenant_id).switch_schema()
|
Database(tenant_id).switch_schema()
|
||||||
|
|
||||||
@@ -48,6 +65,12 @@ def chat(magic_link_code):
|
|||||||
current_app.logger.error(f"Specialist magic link not found in tenant schema: {tenant_id}")
|
current_app.logger.error(f"Specialist magic link not found in tenant schema: {tenant_id}")
|
||||||
return render_template('error.html', message="Specialist configuration not found.")
|
return render_template('error.html', message="Specialist configuration not found.")
|
||||||
|
|
||||||
|
# Get relevant TenantMake
|
||||||
|
tenant_make = TenantMake.query.get(specialist_ml.tenant_make_id)
|
||||||
|
if not tenant_make:
|
||||||
|
current_app.logger.error(f"Tenant make not found: {specialist_ml.tenant_make_id}")
|
||||||
|
return render_template('error.html', message="Tenant make not found.")
|
||||||
|
|
||||||
# Get specialist details
|
# Get specialist details
|
||||||
specialist = Specialist.query.get(specialist_ml.specialist_id)
|
specialist = Specialist.query.get(specialist_ml.specialist_id)
|
||||||
if not specialist:
|
if not specialist:
|
||||||
@@ -55,13 +78,13 @@ def chat(magic_link_code):
|
|||||||
return render_template('error.html', message="Specialist not found.")
|
return render_template('error.html', message="Specialist not found.")
|
||||||
|
|
||||||
# Store necessary information in session
|
# Store necessary information in session
|
||||||
session['tenant_id'] = tenant_id
|
session['tenant'] = tenant.to_dict()
|
||||||
session['specialist_id'] = specialist_ml.specialist_id
|
session['specialist'] = specialist.to_dict()
|
||||||
session['specialist_args'] = specialist_ml.specialist_args or {}
|
session['magic_link'] = specialist_ml.to_dict()
|
||||||
session['magic_link_code'] = magic_link_code
|
session['tenant_make'] = tenant_make.to_dict()
|
||||||
|
|
||||||
# Get customisation options with defaults
|
# Get customisation options with defaults
|
||||||
customisation = get_default_chat_customisation(tenant.chat_customisation_options)
|
customisation = get_default_chat_customisation(tenant_make.chat_customisation_options)
|
||||||
|
|
||||||
# Start a new chat session
|
# Start a new chat session
|
||||||
session['chat_session_id'] = SpecialistServices.start_session()
|
session['chat_session_id'] = SpecialistServices.start_session()
|
||||||
|
|||||||
Reference in New Issue
Block a user