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.

Files changed (78) hide show
  1. iatoolkit/__init__.py +2 -0
  2. iatoolkit/base_company.py +1 -20
  3. iatoolkit/common/routes.py +11 -2
  4. iatoolkit/common/session_manager.py +2 -0
  5. iatoolkit/common/util.py +17 -0
  6. iatoolkit/company_registry.py +1 -2
  7. iatoolkit/iatoolkit.py +41 -5
  8. iatoolkit/locales/en.yaml +167 -0
  9. iatoolkit/locales/es.yaml +163 -0
  10. iatoolkit/repositories/database_manager.py +3 -3
  11. iatoolkit/repositories/document_repo.py +1 -1
  12. iatoolkit/repositories/models.py +2 -3
  13. iatoolkit/repositories/profile_repo.py +0 -4
  14. iatoolkit/services/auth_service.py +14 -9
  15. iatoolkit/services/branding_service.py +32 -22
  16. iatoolkit/services/configuration_service.py +140 -0
  17. iatoolkit/services/dispatcher_service.py +20 -18
  18. iatoolkit/services/document_service.py +5 -2
  19. iatoolkit/services/excel_service.py +15 -11
  20. iatoolkit/services/file_processor_service.py +4 -12
  21. iatoolkit/services/history_service.py +8 -7
  22. iatoolkit/services/i18n_service.py +104 -0
  23. iatoolkit/services/jwt_service.py +7 -9
  24. iatoolkit/services/language_service.py +79 -0
  25. iatoolkit/services/load_documents_service.py +4 -4
  26. iatoolkit/services/mail_service.py +9 -4
  27. iatoolkit/services/onboarding_service.py +10 -4
  28. iatoolkit/services/profile_service.py +58 -38
  29. iatoolkit/services/prompt_manager_service.py +20 -16
  30. iatoolkit/services/query_service.py +15 -14
  31. iatoolkit/services/sql_service.py +6 -2
  32. iatoolkit/services/user_feedback_service.py +16 -14
  33. iatoolkit/static/js/chat_feedback_button.js +57 -87
  34. iatoolkit/static/js/chat_help_content.js +124 -0
  35. iatoolkit/static/js/chat_history_button.js +48 -65
  36. iatoolkit/static/js/chat_main.js +27 -24
  37. iatoolkit/static/js/chat_reload_button.js +28 -45
  38. iatoolkit/static/styles/chat_iatoolkit.css +223 -315
  39. iatoolkit/static/styles/chat_modal.css +63 -97
  40. iatoolkit/static/styles/chat_public.css +107 -0
  41. iatoolkit/static/styles/landing_page.css +0 -1
  42. iatoolkit/templates/_company_header.html +6 -2
  43. iatoolkit/templates/_login_widget.html +42 -0
  44. iatoolkit/templates/base.html +34 -19
  45. iatoolkit/templates/change_password.html +22 -20
  46. iatoolkit/templates/chat.html +58 -27
  47. iatoolkit/templates/chat_modals.html +113 -74
  48. iatoolkit/templates/error.html +12 -13
  49. iatoolkit/templates/forgot_password.html +11 -7
  50. iatoolkit/templates/index.html +8 -3
  51. iatoolkit/templates/login_simulation.html +16 -5
  52. iatoolkit/templates/onboarding_shell.html +0 -1
  53. iatoolkit/templates/signup.html +14 -14
  54. iatoolkit/views/base_login_view.py +12 -1
  55. iatoolkit/views/change_password_view.py +49 -33
  56. iatoolkit/views/forgot_password_view.py +20 -19
  57. iatoolkit/views/help_content_api_view.py +54 -0
  58. iatoolkit/views/history_api_view.py +13 -9
  59. iatoolkit/views/home_view.py +30 -38
  60. iatoolkit/views/init_context_api_view.py +16 -11
  61. iatoolkit/views/llmquery_api_view.py +38 -26
  62. iatoolkit/views/login_simulation_view.py +14 -2
  63. iatoolkit/views/login_view.py +47 -35
  64. iatoolkit/views/logout_api_view.py +26 -22
  65. iatoolkit/views/profile_api_view.py +46 -0
  66. iatoolkit/views/prompt_api_view.py +6 -6
  67. iatoolkit/views/signup_view.py +26 -24
  68. iatoolkit/views/user_feedback_api_view.py +19 -18
  69. iatoolkit/views/verify_user_view.py +30 -29
  70. {iatoolkit-0.63.1.dist-info → iatoolkit-0.67.0.dist-info}/METADATA +40 -22
  71. iatoolkit-0.67.0.dist-info/RECORD +120 -0
  72. iatoolkit-0.67.0.dist-info/licenses/LICENSE +21 -0
  73. iatoolkit/static/styles/chat_info.css +0 -53
  74. iatoolkit/templates/header.html +0 -31
  75. iatoolkit/templates/test.html +0 -9
  76. iatoolkit-0.63.1.dist-info/RECORD +0 -112
  77. {iatoolkit-0.63.1.dist-info → iatoolkit-0.67.0.dist-info}/WHEEL +0 -0
  78. {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 flask import jsonify, request
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
- # 1. Authenticate the request. This handles both session and API Key.
32
- auth_result = self.auth_service.verify()
33
- if not auth_result.get("success"):
34
- return jsonify(auth_result), auth_result.get("status_code")
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
- user_identifier = auth_result.get('user_identifier')
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
- return jsonify({'status': 'OK', 'message': 'El contexto se ha recargado con éxito.'}), 200
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"Error durante la recarga de contexto {user_identifier}: {e}")
59
- return jsonify({"error_message": str(e)}), 500
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, auth_service: AuthService, query_service: QueryService, profile_service: ProfileService):
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
- # 1. Authenticate the API request.
22
- auth_result = self.auth_service.verify()
23
- if not auth_result.get("success"):
24
- return jsonify(auth_result), auth_result.get("status_code")
25
-
26
- # 2. Get the user identifier from the payload.
27
- user_identifier = auth_result.get('user_identifier')
28
-
29
- data = request.get_json()
30
- if not data:
31
- return jsonify({"error": "Invalid JSON body"}), 400
32
-
33
- # 4. Call the unified query service method.
34
- result = self.query_service.llm_query(
35
- company_short_name=company_short_name,
36
- user_identifier=user_identifier,
37
- question=data.get('question', ''),
38
- prompt_name=data.get('prompt_name'),
39
- client_data=data.get('client_data', {}),
40
- files=data.get('files', [])
41
- )
42
- if 'error' in result:
43
- return jsonify(result), 400
44
-
45
- return jsonify(result), 200
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
- """Muestra el formulario para iniciar la simulación."""
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
 
@@ -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', message="Empresa no encontrada"), 404
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
- branding_data = self.branding_service.get_company_branding(company)
44
+ flash(auth_response["message"], 'error')
45
+ home_template = self.utility.get_company_template(company_short_name, "home.html")
42
46
 
43
- return render_template(
44
- 'index.html',
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
- return render_template("error.html",
64
- company=company,
65
- company_short_name=company_short_name,
66
- message=f"Error processing login path: {str(e)}"), 500
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
- # 1. Get the authenticated user's
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", 401)
27
-
28
- company = self.profile_service.get_company_by_short_name(company_short_name)
29
- if not company:
30
- return jsonify({"error": "Empresa no encontrada"}), 404
31
-
32
- # get URL for redirection
33
- url_for_redirect = company.parameters.get('external_urls', {}).get('logout_url')
34
- if not url_for_redirect:
35
- url_for_redirect = url_for('home', company_short_name=company_short_name)
36
-
37
- # clear de session cookie
38
- SessionManager.clear()
39
-
40
- return {
41
- 'status': 'success',
42
- 'url': url_for_redirect,
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"Error inesperado al obtener el historial de consultas para company {company_short_name}: {e}")
36
+ f"unexpected error getting company prompts: {e}")
37
37
  return jsonify({"error_message": str(e)}), 500
@@ -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, session, redirect
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 # 1. Importar 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', message="Empresa no encontrada"), 404
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
- branding_data = self.branding_service.get_company_branding(company)
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
- # Redirigimos al usuario a la página de login
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
- return render_template("error.html",
89
- company=company,
90
- company_short_name=company_short_name,
91
- message=f"Ha ocurrido un error inesperado: {str(e)}"), 500
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
- # get access credentials
24
- auth_result = self.auth_service.verify()
25
- if not auth_result.get("success"):
26
- return jsonify(auth_result), auth_result.get("status_code")
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
- user_identifier = auth_result.get('user_identifier')
29
+ user_identifier = auth_result.get('user_identifier')
29
30
 
30
- data = request.get_json()
31
- if not data:
32
- return jsonify({"error_message": "Cuerpo de la solicitud JSON inválido o faltante"}), 402
31
+ data = request.get_json()
32
+ if not data:
33
+ return jsonify({"error_message": "invalid json body"}), 402
33
34
 
34
- message = data.get("message")
35
- if not message:
36
- return jsonify({"error_message": "Falta el mensaje de feedback"}), 400
37
-
38
- rating = data.get("rating")
39
- if not rating:
40
- return jsonify({"error_message": "Falta la calificación"}), 400
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"Error inesperado al procesar feedback para company {company_short_name}: {e}")
57
-
58
+ f"unexpected error processing feedback for {company_short_name}: {e}")
58
59
  return jsonify({"error_message": str(e)}), 500
59
60