iatoolkit 0.63.1__py3-none-any.whl → 0.67.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 +2 -0
- iatoolkit/base_company.py +1 -20
- 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 +41 -5
- iatoolkit/locales/en.yaml +167 -0
- iatoolkit/locales/es.yaml +163 -0
- iatoolkit/repositories/database_manager.py +3 -3
- iatoolkit/repositories/document_repo.py +1 -1
- iatoolkit/repositories/models.py +2 -3
- iatoolkit/repositories/profile_repo.py +0 -4
- iatoolkit/services/auth_service.py +14 -9
- iatoolkit/services/branding_service.py +32 -22
- iatoolkit/services/configuration_service.py +140 -0
- iatoolkit/services/dispatcher_service.py +20 -18
- 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 +79 -0
- iatoolkit/services/load_documents_service.py +4 -4
- iatoolkit/services/mail_service.py +9 -4
- iatoolkit/services/onboarding_service.py +10 -4
- iatoolkit/services/profile_service.py +58 -38
- iatoolkit/services/prompt_manager_service.py +20 -16
- iatoolkit/services/query_service.py +15 -14
- iatoolkit/services/sql_service.py +6 -2
- 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_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/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 +58 -27
- iatoolkit/templates/chat_modals.html +113 -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 +16 -5
- iatoolkit/templates/onboarding_shell.html +0 -1
- iatoolkit/templates/signup.html +14 -14
- iatoolkit/views/base_login_view.py +12 -1
- iatoolkit/views/change_password_view.py +49 -33
- iatoolkit/views/forgot_password_view.py +20 -19
- iatoolkit/views/help_content_api_view.py +54 -0
- iatoolkit/views/history_api_view.py +13 -9
- iatoolkit/views/home_view.py +30 -38
- 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 +47 -35
- 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 +26 -24
- iatoolkit/views/user_feedback_api_view.py +19 -18
- iatoolkit/views/verify_user_view.py +30 -29
- {iatoolkit-0.63.1.dist-info → iatoolkit-0.67.0.dist-info}/METADATA +40 -22
- iatoolkit-0.67.0.dist-info/RECORD +120 -0
- iatoolkit-0.67.0.dist-info/licenses/LICENSE +21 -0
- 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.67.0.dist-info}/WHEEL +0 -0
- {iatoolkit-0.63.1.dist-info → iatoolkit-0.67.0.dist-info}/top_level.txt +0 -0
|
@@ -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)
|
|
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
15
|
from iatoolkit.services.onboarding_service import OnboardingService
|
|
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)
|
|
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']
|
|
@@ -60,10 +63,13 @@ class LoginView(BaseLoginView):
|
|
|
60
63
|
try:
|
|
61
64
|
return self._handle_login_path(company, 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,12 +80,12 @@ 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
|
onboarding_service: OnboardingService,
|
|
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
|
|
@@ -87,31 +93,34 @@ class FinalizeContextView(MethodView):
|
|
|
87
93
|
self.prompt_service = prompt_service
|
|
88
94
|
self.branding_service = branding_service
|
|
89
95
|
self.onboarding_service = onboarding_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.warning("Fallo crítico: 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)
|
|
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,
|
|
@@ -122,6 +131,9 @@ class FinalizeContextView(MethodView):
|
|
|
122
131
|
prompts = self.prompt_service.get_user_prompts(company_short_name)
|
|
123
132
|
onboarding_cards = self.onboarding_service.get_onboarding_cards(company)
|
|
124
133
|
|
|
134
|
+
# Get the entire 'js_messages' block in the correct language.
|
|
135
|
+
js_translations = self.i18n_service.get_translation_block('js_messages')
|
|
136
|
+
|
|
125
137
|
return render_template(
|
|
126
138
|
"chat.html",
|
|
127
139
|
company_short_name=company_short_name,
|
|
@@ -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
|
iatoolkit/views/signup_view.py
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
# IAToolkit is open source software.
|
|
5
5
|
|
|
6
6
|
from flask.views import MethodView
|
|
7
|
-
from flask import render_template, request, url_for,
|
|
7
|
+
from flask import render_template, request, url_for, redirect, flash
|
|
8
8
|
from iatoolkit.services.profile_service import ProfileService
|
|
9
|
-
from iatoolkit.services.branding_service import BrandingService
|
|
9
|
+
from iatoolkit.services.branding_service import BrandingService
|
|
10
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
10
11
|
from injector import inject
|
|
11
12
|
from itsdangerous import URLSafeTimedSerializer
|
|
12
13
|
import os
|
|
@@ -15,9 +16,12 @@ import os
|
|
|
15
16
|
class SignupView(MethodView):
|
|
16
17
|
@inject
|
|
17
18
|
def __init__(self, profile_service: ProfileService,
|
|
18
|
-
branding_service: BrandingService
|
|
19
|
+
branding_service: BrandingService,
|
|
20
|
+
i18n_service: I18nService):
|
|
19
21
|
self.profile_service = profile_service
|
|
20
22
|
self.branding_service = branding_service # 3. Guardar la instancia
|
|
23
|
+
self.i18n_service = i18n_service
|
|
24
|
+
|
|
21
25
|
self.serializer = URLSafeTimedSerializer(os.getenv("USER_VERIF_KEY"))
|
|
22
26
|
|
|
23
27
|
|
|
@@ -25,23 +29,24 @@ class SignupView(MethodView):
|
|
|
25
29
|
# get company info
|
|
26
30
|
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
27
31
|
if not company:
|
|
28
|
-
return render_template('error.html',
|
|
32
|
+
return render_template('error.html',
|
|
33
|
+
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
29
34
|
|
|
30
|
-
# Obtener los datos de branding
|
|
31
35
|
branding_data = self.branding_service.get_company_branding(company)
|
|
32
|
-
|
|
33
36
|
return render_template('signup.html',
|
|
34
37
|
company=company,
|
|
35
38
|
company_short_name=company_short_name,
|
|
36
39
|
branding=branding_data)
|
|
37
40
|
|
|
38
41
|
def post(self, company_short_name: str):
|
|
39
|
-
# get company info
|
|
40
|
-
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
41
|
-
if not company:
|
|
42
|
-
return render_template('error.html', message="Empresa no encontrada"), 404
|
|
43
|
-
|
|
44
42
|
try:
|
|
43
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
44
|
+
if not company:
|
|
45
|
+
return render_template('error.html',
|
|
46
|
+
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
47
|
+
|
|
48
|
+
branding_data = self.branding_service.get_company_branding(company)
|
|
49
|
+
|
|
45
50
|
first_name = request.form.get('first_name')
|
|
46
51
|
last_name = request.form.get('last_name')
|
|
47
52
|
email = request.form.get('email')
|
|
@@ -62,7 +67,7 @@ class SignupView(MethodView):
|
|
|
62
67
|
verification_url=verification_url)
|
|
63
68
|
|
|
64
69
|
if "error" in response:
|
|
65
|
-
|
|
70
|
+
flash(response["error"], 'error')
|
|
66
71
|
return render_template(
|
|
67
72
|
'signup.html',
|
|
68
73
|
company=company,
|
|
@@ -74,19 +79,16 @@ class SignupView(MethodView):
|
|
|
74
79
|
"email": email,
|
|
75
80
|
"password": password,
|
|
76
81
|
"confirm_password": confirm_password
|
|
77
|
-
},
|
|
78
|
-
alert_message=response["error"]), 400
|
|
79
|
-
|
|
80
|
-
# Guardamos el mensaje de éxito en la sesión
|
|
81
|
-
session['alert_message'] = response["message"]
|
|
82
|
-
session['alert_icon'] = 'success'
|
|
82
|
+
}), 400
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
flash(response["message"], 'success')
|
|
85
85
|
return redirect(url_for('home', company_short_name=company_short_name))
|
|
86
86
|
|
|
87
87
|
except Exception as e:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
message = self.i18n_service.t('errors.templates.processing_error', error=str(e))
|
|
89
|
+
return render_template(
|
|
90
|
+
"error.html",
|
|
91
|
+
company_short_name=company_short_name,
|
|
92
|
+
branding=branding_data,
|
|
93
|
+
message=message
|
|
94
|
+
), 500
|
|
@@ -20,26 +20,28 @@ class UserFeedbackApiView(MethodView):
|
|
|
20
20
|
self.user_feedback_service = user_feedback_service
|
|
21
21
|
|
|
22
22
|
def post(self, company_short_name):
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
try:
|
|
24
|
+
# get access credentials
|
|
25
|
+
auth_result = self.auth_service.verify()
|
|
26
|
+
if not auth_result.get("success"):
|
|
27
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
user_identifier = auth_result.get('user_identifier')
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
data = request.get_json()
|
|
32
|
+
if not data:
|
|
33
|
+
return jsonify({"error_message": "invalid json body"}), 402
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
# these validations are performed also in the frontend
|
|
36
|
+
# the are localized in the front
|
|
37
|
+
message = data.get("message")
|
|
38
|
+
if not message:
|
|
39
|
+
return jsonify({"error_message": "missing feedback message"}), 400
|
|
40
|
+
|
|
41
|
+
rating = data.get("rating")
|
|
42
|
+
if not rating:
|
|
43
|
+
return jsonify({"error_message": "missing rating"}), 400
|
|
41
44
|
|
|
42
|
-
try:
|
|
43
45
|
response = self.user_feedback_service.new_feedback(
|
|
44
46
|
company_short_name=company_short_name,
|
|
45
47
|
message=message,
|
|
@@ -53,7 +55,6 @@ class UserFeedbackApiView(MethodView):
|
|
|
53
55
|
return response, 200
|
|
54
56
|
except Exception as e:
|
|
55
57
|
logging.exception(
|
|
56
|
-
f"
|
|
57
|
-
|
|
58
|
+
f"unexpected error processing feedback for {company_short_name}: {e}")
|
|
58
59
|
return jsonify({"error_message": str(e)}), 500
|
|
59
60
|
|