iatoolkit 0.63.1__py3-none-any.whl → 0.69.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of iatoolkit might be problematic. Click here for more details.
- iatoolkit/__init__.py +0 -2
- iatoolkit/base_company.py +1 -26
- iatoolkit/common/routes.py +11 -2
- iatoolkit/common/session_manager.py +2 -0
- iatoolkit/common/util.py +17 -0
- iatoolkit/company_registry.py +1 -2
- iatoolkit/iatoolkit.py +39 -6
- iatoolkit/locales/en.yaml +167 -0
- iatoolkit/locales/es.yaml +163 -0
- iatoolkit/repositories/database_manager.py +8 -3
- iatoolkit/repositories/document_repo.py +1 -1
- iatoolkit/repositories/models.py +1 -4
- iatoolkit/repositories/profile_repo.py +0 -4
- iatoolkit/services/auth_service.py +14 -9
- iatoolkit/services/branding_service.py +36 -24
- iatoolkit/services/company_context_service.py +145 -0
- iatoolkit/services/configuration_service.py +133 -0
- iatoolkit/services/dispatcher_service.py +51 -48
- iatoolkit/services/document_service.py +5 -2
- iatoolkit/services/excel_service.py +15 -11
- iatoolkit/services/file_processor_service.py +4 -12
- iatoolkit/services/history_service.py +8 -7
- iatoolkit/services/i18n_service.py +104 -0
- iatoolkit/services/jwt_service.py +7 -9
- iatoolkit/services/language_service.py +83 -0
- iatoolkit/services/load_documents_service.py +4 -4
- iatoolkit/services/mail_service.py +9 -4
- iatoolkit/services/profile_service.py +61 -38
- iatoolkit/services/prompt_manager_service.py +20 -16
- iatoolkit/services/query_service.py +19 -15
- iatoolkit/services/search_service.py +11 -4
- iatoolkit/services/sql_service.py +55 -25
- iatoolkit/services/user_feedback_service.py +16 -14
- iatoolkit/static/js/chat_feedback_button.js +57 -87
- iatoolkit/static/js/chat_help_content.js +124 -0
- iatoolkit/static/js/chat_history_button.js +48 -65
- iatoolkit/static/js/chat_main.js +27 -24
- iatoolkit/static/js/chat_onboarding_button.js +6 -0
- iatoolkit/static/js/chat_reload_button.js +28 -45
- iatoolkit/static/styles/chat_iatoolkit.css +223 -315
- iatoolkit/static/styles/chat_modal.css +63 -97
- iatoolkit/static/styles/chat_public.css +107 -0
- iatoolkit/static/styles/landing_page.css +0 -1
- iatoolkit/static/styles/onboarding.css +7 -0
- iatoolkit/templates/_company_header.html +6 -2
- iatoolkit/templates/_login_widget.html +42 -0
- iatoolkit/templates/base.html +34 -19
- iatoolkit/templates/change_password.html +22 -20
- iatoolkit/templates/chat.html +59 -27
- iatoolkit/templates/chat_modals.html +114 -74
- iatoolkit/templates/error.html +12 -13
- iatoolkit/templates/forgot_password.html +11 -7
- iatoolkit/templates/index.html +8 -3
- iatoolkit/templates/login_simulation.html +17 -6
- iatoolkit/templates/onboarding_shell.html +4 -2
- iatoolkit/templates/signup.html +14 -14
- iatoolkit/views/base_login_view.py +19 -9
- iatoolkit/views/change_password_view.py +50 -35
- iatoolkit/views/external_login_view.py +1 -1
- iatoolkit/views/forgot_password_view.py +21 -22
- iatoolkit/views/help_content_api_view.py +54 -0
- iatoolkit/views/history_api_view.py +13 -9
- iatoolkit/views/home_view.py +30 -39
- iatoolkit/views/init_context_api_view.py +16 -11
- iatoolkit/views/llmquery_api_view.py +38 -26
- iatoolkit/views/login_simulation_view.py +14 -2
- iatoolkit/views/login_view.py +52 -40
- iatoolkit/views/logout_api_view.py +26 -22
- iatoolkit/views/profile_api_view.py +46 -0
- iatoolkit/views/prompt_api_view.py +6 -6
- iatoolkit/views/signup_view.py +27 -27
- iatoolkit/views/user_feedback_api_view.py +19 -18
- iatoolkit/views/verify_user_view.py +29 -30
- {iatoolkit-0.63.1.dist-info → iatoolkit-0.69.0.dist-info}/METADATA +40 -22
- iatoolkit-0.69.0.dist-info/RECORD +120 -0
- iatoolkit-0.69.0.dist-info/licenses/LICENSE +21 -0
- iatoolkit/services/onboarding_service.py +0 -43
- iatoolkit/static/styles/chat_info.css +0 -53
- iatoolkit/templates/header.html +0 -31
- iatoolkit/templates/test.html +0 -9
- iatoolkit-0.63.1.dist-info/RECORD +0 -112
- {iatoolkit-0.63.1.dist-info → iatoolkit-0.69.0.dist-info}/WHEEL +0 -0
- {iatoolkit-0.63.1.dist-info → iatoolkit-0.69.0.dist-info}/top_level.txt +0 -0
iatoolkit/views/home_view.py
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# iatoolkit/views/home_view.py
|
|
2
|
-
import
|
|
3
|
-
import os
|
|
4
|
-
from flask import render_template, abort, session, render_template_string
|
|
2
|
+
from flask import render_template, render_template_string
|
|
5
3
|
from flask.views import MethodView
|
|
6
4
|
from injector import inject
|
|
7
5
|
from iatoolkit.services.profile_service import ProfileService
|
|
8
6
|
from iatoolkit.services.branding_service import BrandingService
|
|
9
|
-
import
|
|
7
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
8
|
+
from iatoolkit.common.util import Utility
|
|
10
9
|
|
|
11
10
|
class HomeView(MethodView):
|
|
12
11
|
"""
|
|
@@ -17,53 +16,45 @@ class HomeView(MethodView):
|
|
|
17
16
|
@inject
|
|
18
17
|
def __init__(self,
|
|
19
18
|
profile_service: ProfileService,
|
|
20
|
-
branding_service: BrandingService
|
|
19
|
+
branding_service: BrandingService,
|
|
20
|
+
i18n_service: I18nService,
|
|
21
|
+
utility: Utility):
|
|
21
22
|
self.profile_service = profile_service
|
|
22
23
|
self.branding_service = branding_service
|
|
24
|
+
self.i18n_service = i18n_service
|
|
25
|
+
self.util = utility
|
|
23
26
|
|
|
24
27
|
def get(self, company_short_name: str):
|
|
25
|
-
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
26
|
-
|
|
27
|
-
if not company:
|
|
28
|
-
abort(404, description=f"La empresa '{company_short_name}' no fue encontrada.")
|
|
29
|
-
|
|
30
|
-
branding_data = self.branding_service.get_company_branding(company)
|
|
31
|
-
alert_message = session.pop('alert_message', None)
|
|
32
|
-
alert_icon = session.pop('alert_icon', 'error')
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
# 1. Construimos la ruta al archivo de plantilla específico de la empresa.
|
|
36
|
-
company_template_path = os.path.join(os.getcwd(), f'companies/{company_short_name}/templates/home.html')
|
|
37
|
-
|
|
38
|
-
# 2. Verificamos si el archivo de plantilla personalizado no existe.
|
|
39
|
-
if not os.path.exists(company_template_path):
|
|
40
|
-
return render_template(
|
|
41
|
-
"error.html",
|
|
42
|
-
company=company,
|
|
43
|
-
company_short_name=company_short_name,
|
|
44
|
-
branding=branding_data,
|
|
45
|
-
message=f"La plantilla de la página de inicio para la empresa '{company_short_name}' no está configurada."
|
|
46
|
-
), 500
|
|
47
|
-
|
|
48
|
-
# 3. Si el archivo existe, intentamos leerlo y renderizarlo.
|
|
49
28
|
try:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
29
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
30
|
+
if not company:
|
|
31
|
+
return render_template('error.html',
|
|
32
|
+
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
33
|
+
|
|
34
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
35
|
+
home_template = self.util.get_company_template(company_short_name, "home.html")
|
|
36
|
+
|
|
37
|
+
# 2. Verificamos si el archivo de plantilla personalizado no existe.
|
|
38
|
+
if not home_template:
|
|
39
|
+
message = self.i18n_service.t('errors.templates.home_template_not_found', company_name=company_short_name)
|
|
40
|
+
return render_template(
|
|
41
|
+
"error.html",
|
|
42
|
+
company_short_name=company_short_name,
|
|
43
|
+
branding=branding_data,
|
|
44
|
+
message=message
|
|
45
|
+
), 500
|
|
46
|
+
|
|
47
|
+
# 3. Si el archivo existe, intentamos leerlo y renderizarlo.
|
|
54
48
|
return render_template_string(
|
|
55
|
-
|
|
56
|
-
company=company,
|
|
49
|
+
home_template,
|
|
57
50
|
company_short_name=company_short_name,
|
|
58
51
|
branding=branding_data,
|
|
59
|
-
alert_message=alert_message,
|
|
60
|
-
alert_icon=alert_icon
|
|
61
52
|
)
|
|
62
53
|
except Exception as e:
|
|
54
|
+
message = self.i18n_service.t('errors.templates.processing_error', error=str(e))
|
|
63
55
|
return render_template(
|
|
64
56
|
"error.html",
|
|
65
|
-
company=company,
|
|
66
57
|
company_short_name=company_short_name,
|
|
67
58
|
branding=branding_data,
|
|
68
|
-
message=
|
|
59
|
+
message=message
|
|
69
60
|
), 500
|
|
@@ -3,7 +3,8 @@ from injector import inject
|
|
|
3
3
|
from iatoolkit.services.query_service import QueryService
|
|
4
4
|
from iatoolkit.services.profile_service import ProfileService
|
|
5
5
|
from iatoolkit.services.auth_service import AuthService
|
|
6
|
-
from
|
|
6
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
7
|
+
from flask import jsonify
|
|
7
8
|
import logging
|
|
8
9
|
|
|
9
10
|
|
|
@@ -17,10 +18,12 @@ class InitContextApiView(MethodView):
|
|
|
17
18
|
def __init__(self,
|
|
18
19
|
auth_service: AuthService,
|
|
19
20
|
query_service: QueryService,
|
|
20
|
-
profile_service: ProfileService
|
|
21
|
+
profile_service: ProfileService,
|
|
22
|
+
i18n_service: I18nService):
|
|
21
23
|
self.auth_service = auth_service
|
|
22
24
|
self.query_service = query_service
|
|
23
25
|
self.profile_service = profile_service
|
|
26
|
+
self.i18n_service = i18n_service
|
|
24
27
|
|
|
25
28
|
def post(self, company_short_name: str):
|
|
26
29
|
"""
|
|
@@ -28,14 +31,14 @@ class InitContextApiView(MethodView):
|
|
|
28
31
|
an active web session or by the external_user_id in the JSON payload
|
|
29
32
|
for API calls.
|
|
30
33
|
"""
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
try:
|
|
35
|
+
# 1. Authenticate the request. This handles both session and API Key.
|
|
36
|
+
auth_result = self.auth_service.verify()
|
|
37
|
+
if not auth_result.get("success"):
|
|
38
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
user_identifier = auth_result.get('user_identifier')
|
|
37
41
|
|
|
38
|
-
try:
|
|
39
42
|
# 2. Execute the forced rebuild sequence using the unified identifier.
|
|
40
43
|
self.query_service.session_context.clear_all_context(company_short_name, user_identifier)
|
|
41
44
|
logging.info(f"Context for {company_short_name}/{user_identifier} has been cleared.")
|
|
@@ -52,11 +55,13 @@ class InitContextApiView(MethodView):
|
|
|
52
55
|
)
|
|
53
56
|
|
|
54
57
|
# 3. Respond with JSON, as this is an API endpoint.
|
|
55
|
-
|
|
58
|
+
success_message = self.i18n_service.t('api_responses.context_reloaded_success')
|
|
59
|
+
return jsonify({'status': 'OK', 'message': success_message}), 200
|
|
56
60
|
|
|
57
61
|
except Exception as e:
|
|
58
|
-
logging.exception(f"
|
|
59
|
-
|
|
62
|
+
logging.exception(f"errors while reloading context: {e}")
|
|
63
|
+
error_message = self.i18n_service.t('errors.general.unexpected_error', error=str(e))
|
|
64
|
+
return jsonify({"error_message": error_message}), 500
|
|
60
65
|
|
|
61
66
|
def options(self, company_short_name):
|
|
62
67
|
"""
|
|
@@ -4,6 +4,7 @@ from injector import inject
|
|
|
4
4
|
from iatoolkit.services.query_service import QueryService
|
|
5
5
|
from iatoolkit.services.auth_service import AuthService
|
|
6
6
|
from iatoolkit.services.profile_service import ProfileService
|
|
7
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
7
8
|
import logging
|
|
8
9
|
|
|
9
10
|
class LLMQueryApiView(MethodView):
|
|
@@ -12,34 +13,45 @@ class LLMQueryApiView(MethodView):
|
|
|
12
13
|
"""
|
|
13
14
|
|
|
14
15
|
@inject
|
|
15
|
-
def __init__(self,
|
|
16
|
+
def __init__(self,
|
|
17
|
+
auth_service: AuthService,
|
|
18
|
+
query_service: QueryService,
|
|
19
|
+
profile_service: ProfileService,
|
|
20
|
+
i18n_service: I18nService):
|
|
16
21
|
self.auth_service = auth_service
|
|
17
22
|
self.query_service = query_service
|
|
18
23
|
self.profile_service = profile_service
|
|
24
|
+
self.i18n_service = i18n_service
|
|
19
25
|
|
|
20
26
|
def post(self, company_short_name: str):
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
27
|
+
try:
|
|
28
|
+
# 1. Authenticate the API request.
|
|
29
|
+
auth_result = self.auth_service.verify()
|
|
30
|
+
if not auth_result.get("success"):
|
|
31
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
32
|
+
|
|
33
|
+
# 2. Get the user identifier from the payload.
|
|
34
|
+
user_identifier = auth_result.get('user_identifier')
|
|
35
|
+
|
|
36
|
+
data = request.get_json()
|
|
37
|
+
if not data:
|
|
38
|
+
return jsonify({"error": "Invalid JSON body"}), 400
|
|
39
|
+
|
|
40
|
+
# 4. Call the unified query service method.
|
|
41
|
+
result = self.query_service.llm_query(
|
|
42
|
+
company_short_name=company_short_name,
|
|
43
|
+
user_identifier=user_identifier,
|
|
44
|
+
question=data.get('question', ''),
|
|
45
|
+
prompt_name=data.get('prompt_name'),
|
|
46
|
+
client_data=data.get('client_data', {}),
|
|
47
|
+
files=data.get('files', [])
|
|
48
|
+
)
|
|
49
|
+
if 'error' in result:
|
|
50
|
+
return jsonify(result), 400
|
|
51
|
+
|
|
52
|
+
return jsonify(result), 200
|
|
53
|
+
|
|
54
|
+
except Exception as e:
|
|
55
|
+
logging.exception(
|
|
56
|
+
f"Unexpected error: {e}")
|
|
57
|
+
return jsonify({"error_message": self.i18n_service.t('errors.general.unexpected_error', error=str(e))}), 500
|
|
@@ -10,17 +10,29 @@ from flask.views import MethodView
|
|
|
10
10
|
from flask import render_template, request, Response
|
|
11
11
|
from injector import inject
|
|
12
12
|
from iatoolkit.services.profile_service import ProfileService
|
|
13
|
+
from iatoolkit.services.branding_service import BrandingService
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class LoginSimulationView(MethodView):
|
|
16
17
|
@inject
|
|
17
18
|
def __init__(self,
|
|
18
|
-
profile_service: ProfileService
|
|
19
|
+
profile_service: ProfileService,
|
|
20
|
+
branding_service: BrandingService):
|
|
19
21
|
self.profile_service = profile_service
|
|
22
|
+
self.branding_service = branding_service
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
def get(self, company_short_name: str = None):
|
|
22
|
-
|
|
26
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
27
|
+
if not company:
|
|
28
|
+
return render_template('error.html',
|
|
29
|
+
company_short_name=company_short_name,
|
|
30
|
+
message="Empresa no encontrada"), 404
|
|
31
|
+
|
|
32
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
33
|
+
|
|
23
34
|
return render_template('login_simulation.html',
|
|
35
|
+
branding=branding_data,
|
|
24
36
|
company_short_name=company_short_name
|
|
25
37
|
)
|
|
26
38
|
|
iatoolkit/views/login_view.py
CHANGED
|
@@ -4,15 +4,16 @@
|
|
|
4
4
|
# IAToolkit is open source software.
|
|
5
5
|
|
|
6
6
|
from flask.views import MethodView
|
|
7
|
-
from flask import request, redirect, render_template, url_for
|
|
7
|
+
from flask import (request, redirect, render_template, url_for,
|
|
8
|
+
render_template_string, flash)
|
|
8
9
|
from injector import inject
|
|
9
10
|
from iatoolkit.services.profile_service import ProfileService
|
|
10
|
-
from iatoolkit.services.auth_service import AuthService
|
|
11
11
|
from iatoolkit.services.jwt_service import JWTService
|
|
12
12
|
from iatoolkit.services.query_service import QueryService
|
|
13
13
|
from iatoolkit.services.prompt_manager_service import PromptService
|
|
14
14
|
from iatoolkit.services.branding_service import BrandingService
|
|
15
|
-
from iatoolkit.services.
|
|
15
|
+
from iatoolkit.services.configuration_service import ConfigurationService
|
|
16
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
16
17
|
from iatoolkit.views.base_login_view import BaseLoginView
|
|
17
18
|
import logging
|
|
18
19
|
|
|
@@ -25,8 +26,10 @@ class LoginView(BaseLoginView):
|
|
|
25
26
|
def post(self, company_short_name: str):
|
|
26
27
|
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
27
28
|
if not company:
|
|
28
|
-
return render_template('error.html',
|
|
29
|
+
return render_template('error.html',
|
|
30
|
+
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
29
31
|
|
|
32
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
30
33
|
email = request.form.get('email')
|
|
31
34
|
password = request.form.get('password')
|
|
32
35
|
|
|
@@ -38,15 +41,15 @@ class LoginView(BaseLoginView):
|
|
|
38
41
|
)
|
|
39
42
|
|
|
40
43
|
if not auth_response['success']:
|
|
41
|
-
|
|
44
|
+
flash(auth_response["message"], 'error')
|
|
45
|
+
home_template = self.utility.get_company_template(company_short_name, "home.html")
|
|
42
46
|
|
|
43
|
-
return
|
|
44
|
-
|
|
47
|
+
return render_template_string(
|
|
48
|
+
home_template,
|
|
45
49
|
company_short_name=company_short_name,
|
|
46
50
|
company=company,
|
|
47
51
|
branding=branding_data,
|
|
48
52
|
form_data={"email": email},
|
|
49
|
-
alert_message=auth_response["message"]
|
|
50
53
|
), 400
|
|
51
54
|
|
|
52
55
|
user_identifier = auth_response['user_identifier']
|
|
@@ -58,12 +61,15 @@ class LoginView(BaseLoginView):
|
|
|
58
61
|
|
|
59
62
|
# 2. Delegate the path decision to the centralized logic.
|
|
60
63
|
try:
|
|
61
|
-
return self._handle_login_path(
|
|
64
|
+
return self._handle_login_path(company_short_name, user_identifier, target_url)
|
|
62
65
|
except Exception as e:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
message = self.i18n_service.t('errors.templates.processing_error', error=str(e))
|
|
67
|
+
return render_template(
|
|
68
|
+
"error.html",
|
|
69
|
+
company_short_name=company_short_name,
|
|
70
|
+
branding=branding_data,
|
|
71
|
+
message=message
|
|
72
|
+
), 500
|
|
67
73
|
|
|
68
74
|
|
|
69
75
|
class FinalizeContextView(MethodView):
|
|
@@ -74,44 +80,47 @@ class FinalizeContextView(MethodView):
|
|
|
74
80
|
@inject
|
|
75
81
|
def __init__(self,
|
|
76
82
|
profile_service: ProfileService,
|
|
77
|
-
auth_service: AuthService,
|
|
78
83
|
query_service: QueryService,
|
|
79
84
|
prompt_service: PromptService,
|
|
80
85
|
branding_service: BrandingService,
|
|
81
|
-
|
|
86
|
+
config_service: ConfigurationService,
|
|
82
87
|
jwt_service: JWTService,
|
|
88
|
+
i18n_service: I18nService
|
|
83
89
|
):
|
|
84
90
|
self.profile_service = profile_service
|
|
85
91
|
self.jwt_service = jwt_service
|
|
86
92
|
self.query_service = query_service
|
|
87
93
|
self.prompt_service = prompt_service
|
|
88
94
|
self.branding_service = branding_service
|
|
89
|
-
self.
|
|
95
|
+
self.config_service = config_service
|
|
96
|
+
self.i18n_service = i18n_service
|
|
90
97
|
|
|
91
98
|
def get(self, company_short_name: str, token: str = None):
|
|
92
|
-
session_info = self.profile_service.get_current_session_info()
|
|
93
|
-
if session_info:
|
|
94
|
-
# session exists, internal user
|
|
95
|
-
user_identifier = session_info.get('user_identifier')
|
|
96
|
-
token = ''
|
|
97
|
-
elif token:
|
|
98
|
-
# user identified by api-key
|
|
99
|
-
payload = self.jwt_service.validate_chat_jwt(token)
|
|
100
|
-
if not payload:
|
|
101
|
-
logging.warning("Fallo crítico: No se pudo leer el auth token.")
|
|
102
|
-
return redirect(url_for('index', company_short_name=company_short_name))
|
|
103
|
-
|
|
104
|
-
user_identifier = payload.get('user_identifier')
|
|
105
|
-
else:
|
|
106
|
-
logging.warning("Fallo crítico: missing session information or auth token")
|
|
107
|
-
return redirect(url_for('index', company_short_name=company_short_name))
|
|
108
|
-
|
|
109
|
-
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
110
|
-
if not company:
|
|
111
|
-
return render_template('error.html', message="Empresa no encontrada"), 404
|
|
112
|
-
branding_data = self.branding_service.get_company_branding(company)
|
|
113
|
-
|
|
114
99
|
try:
|
|
100
|
+
session_info = self.profile_service.get_current_session_info()
|
|
101
|
+
if session_info:
|
|
102
|
+
# session exists, internal user
|
|
103
|
+
user_identifier = session_info.get('user_identifier')
|
|
104
|
+
token = ''
|
|
105
|
+
elif token:
|
|
106
|
+
# user identified by api-key
|
|
107
|
+
payload = self.jwt_service.validate_chat_jwt(token)
|
|
108
|
+
if not payload:
|
|
109
|
+
logging.warning("Fallo crítico: No se pudo leer el auth token.")
|
|
110
|
+
return redirect(url_for('home', company_short_name=company_short_name))
|
|
111
|
+
|
|
112
|
+
user_identifier = payload.get('user_identifier')
|
|
113
|
+
else:
|
|
114
|
+
logging.error("missing session information or auth token")
|
|
115
|
+
return redirect(url_for('home', company_short_name=company_short_name))
|
|
116
|
+
|
|
117
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
118
|
+
if not company:
|
|
119
|
+
return render_template('error.html',
|
|
120
|
+
company_short_name=company_short_name,
|
|
121
|
+
message="Empresa no encontrada"), 404
|
|
122
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
123
|
+
|
|
115
124
|
# 2. Finalize the context rebuild (the heavy task).
|
|
116
125
|
self.query_service.finalize_context_rebuild(
|
|
117
126
|
company_short_name=company_short_name,
|
|
@@ -120,7 +129,10 @@ class FinalizeContextView(MethodView):
|
|
|
120
129
|
|
|
121
130
|
# 3. render the chat page.
|
|
122
131
|
prompts = self.prompt_service.get_user_prompts(company_short_name)
|
|
123
|
-
onboarding_cards = self.
|
|
132
|
+
onboarding_cards = self.config_service.get_configuration(company_short_name, 'onboarding_cards')
|
|
133
|
+
|
|
134
|
+
# Get the entire 'js_messages' block in the correct language.
|
|
135
|
+
js_translations = self.i18n_service.get_translation_block('js_messages')
|
|
124
136
|
|
|
125
137
|
return render_template(
|
|
126
138
|
"chat.html",
|
|
@@ -129,12 +141,12 @@ class FinalizeContextView(MethodView):
|
|
|
129
141
|
branding=branding_data,
|
|
130
142
|
prompts=prompts,
|
|
131
143
|
onboarding_cards=onboarding_cards,
|
|
144
|
+
js_translations=js_translations,
|
|
132
145
|
redeem_token=token
|
|
133
146
|
)
|
|
134
147
|
|
|
135
148
|
except Exception as e:
|
|
136
149
|
return render_template("error.html",
|
|
137
|
-
company=company,
|
|
138
150
|
company_short_name=company_short_name,
|
|
139
151
|
branding=branding_data,
|
|
140
152
|
message=f"An unexpected error occurred during context loading: {str(e)}"), 500
|
|
@@ -9,7 +9,7 @@ from injector import inject
|
|
|
9
9
|
from iatoolkit.services.auth_service import AuthService
|
|
10
10
|
from iatoolkit.services.profile_service import ProfileService
|
|
11
11
|
from iatoolkit.common.session_manager import SessionManager
|
|
12
|
-
|
|
12
|
+
import logging
|
|
13
13
|
|
|
14
14
|
class LogoutApiView(MethodView):
|
|
15
15
|
@inject
|
|
@@ -20,26 +20,30 @@ class LogoutApiView(MethodView):
|
|
|
20
20
|
self.auth_service = auth_service
|
|
21
21
|
|
|
22
22
|
def get(self, company_short_name: str = None):
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
23
|
+
try:
|
|
24
|
+
# 1. Get the authenticated user's
|
|
25
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
26
|
+
if not auth_result.get("success"):
|
|
27
|
+
return jsonify(auth_result), auth_result.get("status_code", 401)
|
|
28
|
+
|
|
29
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
30
|
+
if not company:
|
|
31
|
+
return jsonify({"error": "company not found."}), 404
|
|
32
|
+
|
|
33
|
+
# get URL for redirection
|
|
34
|
+
url_for_redirect = company.parameters.get('external_urls', {}).get('logout_url')
|
|
35
|
+
if not url_for_redirect:
|
|
36
|
+
url_for_redirect = url_for('home', company_short_name=company_short_name)
|
|
37
|
+
|
|
38
|
+
# clear de session cookie
|
|
39
|
+
SessionManager.clear()
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
'status': 'success',
|
|
43
|
+
'url': url_for_redirect,
|
|
44
|
+
}, 200
|
|
45
|
+
except Exception as e:
|
|
46
|
+
logging.exception(f"Unexpected error: {e}")
|
|
47
|
+
return {'status': 'error'}, 500
|
|
44
48
|
|
|
45
49
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# iatoolkit/views/profile_api_view.py
|
|
2
|
+
from flask import request, jsonify
|
|
3
|
+
from flask.views import MethodView
|
|
4
|
+
from injector import inject
|
|
5
|
+
from iatoolkit.services.auth_service import AuthService
|
|
6
|
+
from iatoolkit.services.profile_service import ProfileService
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UserLanguageApiView(MethodView):
|
|
10
|
+
"""
|
|
11
|
+
API endpoint for managing user language preferences.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@inject
|
|
15
|
+
def __init__(self,
|
|
16
|
+
auth_service: AuthService,
|
|
17
|
+
profile_service: ProfileService):
|
|
18
|
+
self.auth_service = auth_service
|
|
19
|
+
self.profile_service = profile_service
|
|
20
|
+
|
|
21
|
+
def post(self):
|
|
22
|
+
"""
|
|
23
|
+
Handles POST requests to update the user's preferred language.
|
|
24
|
+
Expects a JSON body with a 'language' key, e.g., {"language": "en"}.
|
|
25
|
+
"""
|
|
26
|
+
# 1. Authenticate the user from the current session.
|
|
27
|
+
auth_result = self.auth_service.verify()
|
|
28
|
+
if not auth_result.get("success"):
|
|
29
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
30
|
+
|
|
31
|
+
user_identifier = auth_result.get('user_identifier')
|
|
32
|
+
|
|
33
|
+
# 2. Validate request body
|
|
34
|
+
data = request.get_json()
|
|
35
|
+
if not data or 'language' not in data:
|
|
36
|
+
return jsonify({"error_message": "Missing 'language' field in request body"}), 400
|
|
37
|
+
|
|
38
|
+
new_lang = data.get('language')
|
|
39
|
+
|
|
40
|
+
# 3. Call the service to perform the update
|
|
41
|
+
update_result = self.profile_service.update_user_language(user_identifier, new_lang)
|
|
42
|
+
|
|
43
|
+
if not update_result.get('success'):
|
|
44
|
+
return jsonify(update_result), 400
|
|
45
|
+
|
|
46
|
+
return jsonify({"message": "Language preference updated successfully"}), 200
|
|
@@ -20,12 +20,12 @@ class PromptApiView(MethodView):
|
|
|
20
20
|
self.prompt_service = prompt_service
|
|
21
21
|
|
|
22
22
|
def get(self, company_short_name):
|
|
23
|
-
# get access credentials
|
|
24
|
-
auth_result = self.auth_service.verify(anonymous=True)
|
|
25
|
-
if not auth_result.get("success"):
|
|
26
|
-
return jsonify(auth_result), auth_result.get('status_code')
|
|
27
|
-
|
|
28
23
|
try:
|
|
24
|
+
# get access credentials
|
|
25
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
26
|
+
if not auth_result.get("success"):
|
|
27
|
+
return jsonify(auth_result), auth_result.get('status_code')
|
|
28
|
+
|
|
29
29
|
response = self.prompt_service.get_user_prompts(company_short_name)
|
|
30
30
|
if "error" in response:
|
|
31
31
|
return {'error_message': response["error"]}, 402
|
|
@@ -33,5 +33,5 @@ class PromptApiView(MethodView):
|
|
|
33
33
|
return response, 200
|
|
34
34
|
except Exception as e:
|
|
35
35
|
logging.exception(
|
|
36
|
-
f"
|
|
36
|
+
f"unexpected error getting company prompts: {e}")
|
|
37
37
|
return jsonify({"error_message": str(e)}), 500
|