iatoolkit 0.8.1__py3-none-any.whl → 0.63.4__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 (159) hide show
  1. iatoolkit/__init__.py +8 -34
  2. iatoolkit/base_company.py +14 -3
  3. iatoolkit/common/routes.py +83 -52
  4. iatoolkit/common/session_manager.py +0 -1
  5. iatoolkit/common/util.py +0 -27
  6. iatoolkit/iatoolkit.py +61 -46
  7. iatoolkit/infra/llm_client.py +7 -8
  8. iatoolkit/infra/openai_adapter.py +1 -1
  9. iatoolkit/infra/redis_session_manager.py +48 -2
  10. iatoolkit/repositories/database_manager.py +17 -2
  11. iatoolkit/repositories/models.py +31 -6
  12. iatoolkit/repositories/profile_repo.py +7 -2
  13. iatoolkit/services/auth_service.py +188 -0
  14. iatoolkit/services/branding_service.py +147 -0
  15. iatoolkit/services/dispatcher_service.py +10 -40
  16. iatoolkit/services/excel_service.py +15 -15
  17. iatoolkit/services/history_service.py +3 -12
  18. iatoolkit/services/jwt_service.py +15 -24
  19. iatoolkit/services/onboarding_service.py +43 -0
  20. iatoolkit/services/profile_service.py +97 -44
  21. iatoolkit/services/query_service.py +124 -81
  22. iatoolkit/services/tasks_service.py +1 -1
  23. iatoolkit/services/user_feedback_service.py +67 -31
  24. iatoolkit/services/user_session_context_service.py +112 -54
  25. iatoolkit/static/images/fernando.jpeg +0 -0
  26. iatoolkit/static/js/{chat_feedback.js → chat_feedback_button.js} +6 -11
  27. iatoolkit/static/js/chat_history_button.js +126 -0
  28. iatoolkit/static/js/chat_logout_button.js +36 -0
  29. iatoolkit/static/js/chat_main.js +130 -220
  30. iatoolkit/static/js/chat_onboarding_button.js +97 -0
  31. iatoolkit/static/js/chat_prompt_manager.js +94 -0
  32. iatoolkit/static/js/chat_reload_button.js +52 -0
  33. iatoolkit/static/styles/chat_iatoolkit.css +329 -507
  34. iatoolkit/static/styles/chat_modal.css +95 -56
  35. iatoolkit/static/styles/landing_page.css +182 -0
  36. iatoolkit/static/styles/onboarding.css +169 -0
  37. iatoolkit/system_prompts/query_main.prompt +3 -12
  38. iatoolkit/templates/_company_header.html +20 -0
  39. iatoolkit/templates/_login_widget.html +40 -0
  40. iatoolkit/templates/base.html +8 -3
  41. iatoolkit/templates/change_password.html +54 -37
  42. iatoolkit/templates/chat.html +149 -66
  43. iatoolkit/templates/chat_modals.html +47 -18
  44. iatoolkit/templates/error.html +41 -8
  45. iatoolkit/templates/forgot_password.html +37 -24
  46. iatoolkit/templates/index.html +140 -0
  47. iatoolkit/templates/login_simulation.html +34 -0
  48. iatoolkit/templates/onboarding_shell.html +105 -0
  49. iatoolkit/templates/signup.html +64 -66
  50. iatoolkit/views/base_login_view.py +81 -0
  51. iatoolkit/views/change_password_view.py +23 -12
  52. iatoolkit/views/external_login_view.py +61 -28
  53. iatoolkit/views/{file_store_view.py → file_store_api_view.py} +9 -2
  54. iatoolkit/views/forgot_password_view.py +23 -13
  55. iatoolkit/views/history_api_view.py +52 -0
  56. iatoolkit/views/home_view.py +58 -25
  57. iatoolkit/views/index_view.py +14 -0
  58. iatoolkit/views/init_context_api_view.py +68 -0
  59. iatoolkit/views/llmquery_api_view.py +45 -0
  60. iatoolkit/views/login_simulation_view.py +81 -0
  61. iatoolkit/views/login_view.py +118 -34
  62. iatoolkit/views/logout_api_view.py +45 -0
  63. iatoolkit/views/{prompt_view.py → prompt_api_view.py} +7 -7
  64. iatoolkit/views/signup_view.py +38 -29
  65. iatoolkit/views/{tasks_view.py → tasks_api_view.py} +10 -36
  66. iatoolkit/views/tasks_review_api_view.py +55 -0
  67. iatoolkit/views/{user_feedback_view.py → user_feedback_api_view.py} +16 -31
  68. iatoolkit/views/verify_user_view.py +13 -8
  69. {iatoolkit-0.8.1.dist-info → iatoolkit-0.63.4.dist-info}/METADATA +2 -2
  70. iatoolkit-0.63.4.dist-info/RECORD +113 -0
  71. {iatoolkit-0.8.1.dist-info → iatoolkit-0.63.4.dist-info}/top_level.txt +0 -1
  72. iatoolkit/common/auth.py +0 -200
  73. iatoolkit/static/images/arrow_up.png +0 -0
  74. iatoolkit/static/images/diagrama_iatoolkit.jpg +0 -0
  75. iatoolkit/static/images/logo_clinica.png +0 -0
  76. iatoolkit/static/images/logo_iatoolkit.png +0 -0
  77. iatoolkit/static/images/logo_maxxa.png +0 -0
  78. iatoolkit/static/images/logo_notaria.png +0 -0
  79. iatoolkit/static/images/logo_tarjeta.png +0 -0
  80. iatoolkit/static/images/logo_umayor.png +0 -0
  81. iatoolkit/static/images/upload.png +0 -0
  82. iatoolkit/static/js/chat_history.js +0 -117
  83. iatoolkit/templates/home.html +0 -201
  84. iatoolkit/templates/login.html +0 -43
  85. iatoolkit/views/chat_token_request_view.py +0 -98
  86. iatoolkit/views/chat_view.py +0 -51
  87. iatoolkit/views/download_file_view.py +0 -58
  88. iatoolkit/views/external_chat_login_view.py +0 -88
  89. iatoolkit/views/history_view.py +0 -57
  90. iatoolkit/views/llmquery_view.py +0 -65
  91. iatoolkit/views/tasks_review_view.py +0 -83
  92. iatoolkit-0.8.1.dist-info/RECORD +0 -175
  93. tests/__init__.py +0 -5
  94. tests/common/__init__.py +0 -0
  95. tests/common/test_auth.py +0 -279
  96. tests/common/test_routes.py +0 -42
  97. tests/common/test_session_manager.py +0 -59
  98. tests/common/test_util.py +0 -444
  99. tests/companies/__init__.py +0 -5
  100. tests/conftest.py +0 -36
  101. tests/infra/__init__.py +0 -5
  102. tests/infra/connectors/__init__.py +0 -5
  103. tests/infra/connectors/test_google_drive_connector.py +0 -107
  104. tests/infra/connectors/test_local_file_connector.py +0 -85
  105. tests/infra/connectors/test_s3_connector.py +0 -95
  106. tests/infra/test_call_service.py +0 -92
  107. tests/infra/test_database_manager.py +0 -59
  108. tests/infra/test_gemini_adapter.py +0 -137
  109. tests/infra/test_google_chat_app.py +0 -68
  110. tests/infra/test_llm_client.py +0 -165
  111. tests/infra/test_llm_proxy.py +0 -122
  112. tests/infra/test_mail_app.py +0 -94
  113. tests/infra/test_openai_adapter.py +0 -105
  114. tests/infra/test_redis_session_manager_service.py +0 -117
  115. tests/repositories/__init__.py +0 -5
  116. tests/repositories/test_database_manager.py +0 -87
  117. tests/repositories/test_document_repo.py +0 -76
  118. tests/repositories/test_llm_query_repo.py +0 -340
  119. tests/repositories/test_models.py +0 -38
  120. tests/repositories/test_profile_repo.py +0 -142
  121. tests/repositories/test_tasks_repo.py +0 -76
  122. tests/repositories/test_vs_repo.py +0 -107
  123. tests/services/__init__.py +0 -5
  124. tests/services/test_dispatcher_service.py +0 -274
  125. tests/services/test_document_service.py +0 -181
  126. tests/services/test_excel_service.py +0 -208
  127. tests/services/test_file_processor_service.py +0 -121
  128. tests/services/test_history_service.py +0 -164
  129. tests/services/test_jwt_service.py +0 -255
  130. tests/services/test_load_documents_service.py +0 -112
  131. tests/services/test_mail_service.py +0 -70
  132. tests/services/test_profile_service.py +0 -379
  133. tests/services/test_prompt_manager_service.py +0 -190
  134. tests/services/test_query_service.py +0 -243
  135. tests/services/test_search_service.py +0 -39
  136. tests/services/test_sql_service.py +0 -160
  137. tests/services/test_tasks_service.py +0 -252
  138. tests/services/test_user_feedback_service.py +0 -389
  139. tests/services/test_user_session_context_service.py +0 -132
  140. tests/views/__init__.py +0 -5
  141. tests/views/test_change_password_view.py +0 -191
  142. tests/views/test_chat_token_request_view.py +0 -188
  143. tests/views/test_chat_view.py +0 -98
  144. tests/views/test_download_file_view.py +0 -149
  145. tests/views/test_external_chat_login_view.py +0 -120
  146. tests/views/test_external_login_view.py +0 -102
  147. tests/views/test_file_store_view.py +0 -128
  148. tests/views/test_forgot_password_view.py +0 -142
  149. tests/views/test_history_view.py +0 -336
  150. tests/views/test_home_view.py +0 -61
  151. tests/views/test_llm_query_view.py +0 -154
  152. tests/views/test_login_view.py +0 -114
  153. tests/views/test_prompt_view.py +0 -111
  154. tests/views/test_signup_view.py +0 -140
  155. tests/views/test_tasks_review_view.py +0 -104
  156. tests/views/test_tasks_view.py +0 -130
  157. tests/views/test_user_feedback_view.py +0 -214
  158. tests/views/test_verify_user_view.py +0 -110
  159. {iatoolkit-0.8.1.dist-info → iatoolkit-0.63.4.dist-info}/WHEEL +0 -0
@@ -1,336 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Product: IAToolkit
3
- #
4
- # IAToolkit is open source software.
5
-
6
- import pytest
7
- from unittest.mock import MagicMock, patch
8
- from flask import Flask
9
- from iatoolkit.views.history_view import HistoryView
10
- from iatoolkit.services.history_service import HistoryService
11
- from iatoolkit.common.auth import IAuthentication
12
-
13
-
14
- class TestHistoryView:
15
- @staticmethod
16
- def create_app():
17
- app = Flask(__name__)
18
- app.testing = True
19
- return app
20
-
21
- @pytest.fixture(autouse=True)
22
- def setup(self):
23
- self.app = self.create_app()
24
- self.client = self.app.test_client()
25
- self.history_service = MagicMock(spec=HistoryService)
26
- self.iauthentication = MagicMock(spec=IAuthentication)
27
-
28
- self.iauthentication.verify.return_value = {
29
- 'success': True,
30
- 'company_id': 101,
31
- 'external_user_id': 'test_user_id'
32
- }
33
-
34
- # register the view
35
- self.history_view = HistoryView.as_view("history",
36
- history_service=self.history_service,
37
- iauthentication=self.iauthentication)
38
- self.app.add_url_rule('/<company_short_name>/history',
39
- view_func=self.history_view,
40
- methods=["POST"])
41
-
42
- def test_post_when_missing_data(self):
43
- """Test when no JSON data is provided"""
44
- response = self.client.post('/my_company/history',
45
- json={})
46
-
47
- assert response.status_code == 400
48
- assert response.json["error_message"] == "Cuerpo de la solicitud JSON inválido o faltante"
49
- self.history_service.get_history.assert_not_called()
50
-
51
- def test_post_when_invalid_json(self):
52
- """Test when invalid JSON is provided"""
53
- response = self.client.post('/my_company/history',
54
- data='invalid json',
55
- content_type='application/json')
56
-
57
- assert response.status_code == 400
58
- assert response.json["error_message"] == "Cuerpo de la solicitud JSON inválido o faltante"
59
- self.history_service.get_history.assert_not_called()
60
-
61
- def test_post_when_auth_error(self):
62
- """Test when authentication fails"""
63
- self.iauthentication.verify.return_value = {
64
- 'success': False,
65
- 'error_message': 'Usuario no autenticado'
66
- }
67
-
68
- response = self.client.post('/my_company/history',
69
- json={'external_user_id': 'flibe'})
70
-
71
- assert response.status_code == 401
72
- assert response.json["error_message"] == 'Usuario no autenticado'
73
- self.history_service.get_history.assert_not_called()
74
-
75
- def test_post_when_missing_external_user_id(self):
76
- """Test when external_user_id is missing"""
77
- response = self.client.post('/my_company/history',
78
- json={})
79
-
80
- assert response.status_code == 400
81
- assert response.json["error_message"] == "Cuerpo de la solicitud JSON inválido o faltante"
82
- self.history_service.get_history.assert_not_called()
83
-
84
- def test_post_when_service_error(self):
85
- """Test when service returns an error"""
86
- self.history_service.get_history.return_value = {
87
- 'error': 'Error al obtener historial'
88
- }
89
-
90
- response = self.client.post('/my_company/history',
91
- json={'external_user_id': 'flibe'})
92
-
93
- assert response.status_code == 402
94
- assert response.json == {'error_message': 'Error al obtener historial'}
95
-
96
- def test_post_when_service_exception(self):
97
- """Test when service raises an exception"""
98
- self.history_service.get_history.side_effect = Exception('Service error')
99
-
100
- response = self.client.post('/my_company/history',
101
- json={'external_user_id': 'flibe'})
102
-
103
- assert response.status_code == 500
104
- assert response.json["error_message"] == 'Service error'
105
-
106
- def test_post_when_ok_with_external_user_id(self):
107
- """Test successful request with external_user_id"""
108
- mock_history = {
109
- 'success': True,
110
- 'history': [
111
- {
112
- 'id': 1,
113
- 'question': 'Test question',
114
- 'answer': 'Test answer',
115
- 'created_at': '2024-01-15T10:30:00Z'
116
- }
117
- ],
118
- 'count': 1
119
- }
120
- self.history_service.get_history.return_value = mock_history
121
-
122
- response = self.client.post('/my_company/history',
123
- json={'external_user_id': 'flibe'})
124
-
125
- assert response.status_code == 200
126
- assert response.json == mock_history
127
-
128
- # Verify service was called correctly
129
- self.history_service.get_history.assert_called_once_with(
130
- company_short_name='my_company',
131
- external_user_id='flibe',
132
- local_user_id=0
133
- )
134
-
135
- def test_post_when_ok_with_local_user_id(self):
136
- """Test successful request with local_user_id"""
137
- mock_history = {
138
- 'success': True,
139
- 'history': [
140
- {
141
- 'id': 1,
142
- 'question': 'Test question',
143
- 'answer': 'Test answer',
144
- 'created_at': '2024-01-15T10:30:00Z'
145
- }
146
- ],
147
- 'count': 1
148
- }
149
-
150
- self.history_service.get_history.return_value = mock_history
151
-
152
- response = self.client.post('/my_company/history',
153
- json={
154
- 'external_user_id': 'flibe',
155
- 'local_user_id': 123
156
- })
157
-
158
- assert response.status_code == 200
159
- assert response.json == mock_history
160
-
161
- # Verify service was called correctly
162
- self.history_service.get_history.assert_called_once_with(
163
- company_short_name='my_company',
164
- external_user_id='flibe',
165
- local_user_id=123
166
- )
167
-
168
- def test_post_when_ok_with_both_user_ids(self):
169
- """Test successful request with both user IDs"""
170
- mock_history = {
171
- 'success': True,
172
- 'history': [
173
- {
174
- 'id': 1,
175
- 'question': 'Test question',
176
- 'answer': 'Test answer',
177
- 'created_at': '2024-01-15T10:30:00Z'
178
- }
179
- ],
180
- 'count': 1
181
- }
182
-
183
- self.history_service.get_history.return_value = mock_history
184
-
185
- response = self.client.post('/my_company/history',
186
- json={
187
- 'external_user_id': 'flibe',
188
- 'local_user_id': 456
189
- })
190
-
191
- assert response.status_code == 200
192
- assert response.json == mock_history
193
-
194
- # Verify service was called correctly
195
- self.history_service.get_history.assert_called_once_with(
196
- company_short_name='my_company',
197
- external_user_id='flibe',
198
- local_user_id=456
199
- )
200
-
201
- def test_post_with_empty_history(self):
202
- """Test when service returns empty history"""
203
- mock_history = {
204
- 'success': True,
205
- 'history': [],
206
- 'count': 0
207
- }
208
-
209
- self.history_service.get_history.return_value = mock_history
210
-
211
- response = self.client.post('/my_company/history',
212
- json={'external_user_id': 'flibe'})
213
-
214
- assert response.status_code == 200
215
- assert response.json == mock_history
216
- assert response.json['count'] == 0
217
-
218
- def test_post_with_large_history(self):
219
- """Test with large history response"""
220
- mock_history = {
221
- 'success': True,
222
- 'history': [
223
- {
224
- 'id': i,
225
- 'question': f'Question {i}',
226
- 'answer': f'Answer {i}',
227
- 'created_at': '2024-01-15T10:30:00Z'
228
- } for i in range(1, 11)
229
- ],
230
- 'count': 10
231
- }
232
-
233
- self.history_service.get_history.return_value = mock_history
234
-
235
- response = self.client.post('/my_company/history',
236
- json={'external_user_id': 'flibe'})
237
-
238
- assert response.status_code == 200
239
- assert response.json == mock_history
240
- assert response.json['count'] == 10
241
- assert len(response.json['history']) == 10
242
-
243
- @patch("iatoolkit.views.history_view.render_template")
244
- def test_post_exception_with_local_user_id(self, mock_render_template):
245
- """Test exception handling when local_user_id is present"""
246
- mock_render_template.return_value = "<html><body>Error</body></html>"
247
- self.history_service.get_history.side_effect = Exception('Service error')
248
-
249
- response = self.client.post('/my_company/history',
250
- json={
251
- 'external_user_id': 'flibe',
252
- 'local_user_id': 123
253
- })
254
-
255
- assert response.status_code == 500
256
- mock_render_template.assert_called_once_with(
257
- "error.html",
258
- message="Ha ocurrido un error inesperado."
259
- )
260
-
261
- def test_post_exception_without_local_user_id(self):
262
- """Test exception handling when local_user_id is not present"""
263
- self.history_service.get_history.side_effect = Exception('Service error')
264
-
265
- response = self.client.post('/my_company/history',
266
- json={'external_user_id': 'flibe'})
267
-
268
- assert response.status_code == 500
269
- assert response.json["error_message"] == 'Service error'
270
-
271
- def test_post_authentication_verification_called(self):
272
- """Test that authentication verification is called correctly"""
273
- mock_history = {
274
- 'success': True,
275
- 'history': [],
276
- 'count': 0
277
- }
278
-
279
- self.history_service.get_history.return_value = mock_history
280
-
281
- response = self.client.post('/my_company/history',
282
- json={'external_user_id': 'test_user'})
283
-
284
- assert response.status_code == 200
285
-
286
- # Verify authentication was called correctly
287
- self.iauthentication.verify.assert_called_once_with('my_company', 'test_user')
288
-
289
- def test_post_different_company(self):
290
- """Test with different company short name"""
291
- mock_history = {
292
- 'success': True,
293
- 'history': [],
294
- 'count': 0
295
- }
296
-
297
- self.history_service.get_history.return_value = mock_history
298
-
299
- response = self.client.post('/test_company/history',
300
- json={'external_user_id': 'flibe'})
301
-
302
- assert response.status_code == 200
303
-
304
- # Verify service was called with correct company
305
- self.history_service.get_history.assert_called_once_with(
306
- company_short_name='test_company',
307
- external_user_id='flibe',
308
- local_user_id=0
309
- )
310
-
311
- def test_post_with_additional_fields_ignored(self):
312
- """Test that additional fields in JSON are ignored"""
313
- mock_history = {
314
- 'success': True,
315
- 'history': [],
316
- 'count': 0
317
- }
318
-
319
- self.history_service.get_history.return_value = mock_history
320
-
321
- response = self.client.post('/my_company/history',
322
- json={
323
- 'external_user_id': 'flibe',
324
- 'local_user_id': 123,
325
- 'extra_field': 'should_be_ignored',
326
- 'another_field': 456
327
- })
328
-
329
- assert response.status_code == 200
330
-
331
- # Verify only expected fields are passed to service
332
- self.history_service.get_history.assert_called_once_with(
333
- company_short_name='my_company',
334
- external_user_id='flibe',
335
- local_user_id=123
336
- )
@@ -1,61 +0,0 @@
1
- import pytest
2
- from flask import Flask
3
- from unittest.mock import MagicMock, patch
4
- import os
5
-
6
- # Asegúrate de que las importaciones sean correctas y existan
7
- from iatoolkit.views.home_view import HomeView
8
- from iatoolkit.services.profile_service import ProfileService
9
- from iatoolkit.repositories.models import Company
10
-
11
-
12
- # Ya no necesitamos JWTService, ChatTokenRequestView, etc.
13
-
14
- class TestHomeView:
15
- @staticmethod
16
- def create_app():
17
- """Configura la aplicación Flask para pruebas."""
18
- app = Flask(__name__)
19
- app.testing = True
20
- return app
21
-
22
- @pytest.fixture(autouse=True)
23
- def setup(self):
24
- """Configura el cliente y el mock antes de cada test."""
25
- self.app = self.create_app()
26
- self.client = self.app.test_client()
27
- self.profile_service = MagicMock(spec=ProfileService)
28
- self.test_company = Company(id=1, name='a company', short_name='test_company')
29
- self.profile_service.get_companies.return_value = [self.test_company]
30
-
31
- # Registrar únicamente la vista que estamos probando.
32
- # No necesitamos registrar las otras vistas que han sido eliminadas.
33
- view = HomeView.as_view("home", profile_service=self.profile_service)
34
- self.app.add_url_rule("/", view_func=view, methods=["GET"])
35
-
36
- @patch("iatoolkit.views.home_view.render_template")
37
- @patch.dict(os.environ, {"IATOOLKIT_API_KEY": "una_api_key_de_prueba_segura"})
38
- def test_get_home_page(self, mock_render_template):
39
- """
40
- Prueba que la página de inicio se renderice correctamente sin los parámetros obsoletos.
41
- """
42
- mock_render_template.return_value = "<html><body><h1>Home Page</h1></body></html>"
43
-
44
- # Ya no necesitamos el contexto de la petición para generar las URLs
45
- response = self.client.get("/")
46
-
47
- assert response.status_code == 200
48
- assert b"<h1>Home Page</h1>" in response.data
49
-
50
- # La aserción ahora debe reflejar los argumentos actuales de render_template en HomeView
51
- mock_render_template.assert_called_once_with(
52
- "home.html",
53
- companies=[self.test_company],
54
- is_mobile=False,
55
- alert_icon=None,
56
- alert_message=None,
57
- api_key="una_api_key_de_prueba_segura",
58
- # Hemos eliminado los siguientes parámetros obsoletos:
59
- # chat_token_request_url=...
60
- # public_chat_url_template=...
61
- )
@@ -1,154 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Product: IAToolkit
3
- #
4
- # IAToolkit is open source software.
5
-
6
- import pytest
7
- from unittest.mock import MagicMock, patch
8
- from flask import Flask
9
- from iatoolkit.repositories.models import ApiKey, Company
10
- from iatoolkit.services.query_service import QueryService
11
- from iatoolkit.views.llmquery_view import LLMQueryView
12
- from datetime import datetime, timezone
13
- from iatoolkit.common.session_manager import SessionManager
14
- from iatoolkit.common.auth import IAuthentication
15
-
16
- class TestLLMQueryView:
17
- @staticmethod
18
- def create_app():
19
- """Configura la aplicación Flask para pruebas."""
20
- app = Flask(__name__)
21
- app.testing = True
22
- app.config['TESTING'] = True
23
- app.config['SECRET_KEY'] = 'test_key'
24
-
25
- return app
26
-
27
- @pytest.fixture(autouse=True)
28
- def setup(self):
29
- self.app = self.create_app()
30
- self.client = self.app.test_client()
31
- self.query_service = MagicMock(spec=QueryService)
32
- self.iauthentication = MagicMock(spec=IAuthentication)
33
-
34
- self.iauthentication.verify.return_value = {
35
- 'success': True,
36
- 'company_id': 101,
37
- 'external_user_id': 'test_user_id'
38
- }
39
-
40
- self.test_data = {
41
- "question": "¿Pregunta con error?",
42
- "files": []
43
- }
44
-
45
- @self.app.route('/login')
46
- def login():
47
- return "Login Page", 200
48
-
49
- # Configurar la vista
50
- view = LLMQueryView.as_view('llm_query',
51
- query_service=self.query_service,
52
- iauthentication=self.iauthentication)
53
- self.app.add_url_rule('/<company_short_name>/query', view_func=view)
54
-
55
- self.query_service.llm_query.return_value = {
56
- "answer": "Respuesta exitosa",
57
- "aditional_data": {}
58
- }
59
-
60
- # Mock values
61
- self.api_key = ApiKey(key="test_key", company_id=100)
62
- self.api_key.company = Company(id=100, name="Test Company", short_name="test_company")
63
-
64
- mock_session_values = {
65
- 'user': {'id': 1, 'username': 'test_user'},
66
- 'user_id': 1,
67
- 'company_id': 100,
68
- 'company_short_name': 'test_company',
69
- 'last_activity': datetime.now(timezone.utc).timestamp()
70
- }
71
-
72
- # Mockear SessionManager.get
73
- mock_session_manager = MagicMock(spec=SessionManager) # <- Mock de la clase
74
- mock_session_manager.get.side_effect = lambda key, default=None: mock_session_values.get(key, default)
75
-
76
- with patch('iatoolkit.common.auth.SessionManager', new=mock_session_manager):
77
- with self.app.test_request_context(): # Necesario para Flask
78
- yield
79
-
80
- def test_post_success(self):
81
- api_data = {
82
- "question": "¿Cuál es el significado de la vida?",
83
- "external_user_id": "test_user_id",
84
- "files": ["archivo1.txt", "archivo2.txt"]
85
- }
86
-
87
- # Realizar la solicitud
88
- response = self.client.post(
89
- '/test_company/query',
90
- json=api_data
91
- )
92
-
93
- # Verificaciones
94
- assert response.status_code == 200
95
- assert response.json['answer'] == "Respuesta exitosa"
96
-
97
- self.query_service.llm_query.assert_called_once_with(
98
- company_short_name='test_company',
99
- local_user_id=None,
100
- external_user_id='test_user_id',
101
- question=api_data["question"],
102
- prompt_name= None,
103
- client_data={},
104
- files=api_data["files"]
105
- )
106
-
107
-
108
- def test_post_when_missing_data(self):
109
- response = self.client.post(
110
- '/test_company/query',
111
- json={}
112
- )
113
-
114
- assert response.status_code == 400
115
- assert response.json["error_message"] == "Cuerpo de la solicitud JSON inválido o faltante"
116
-
117
-
118
- def test_post_when_auth_error(self):
119
- self.iauthentication.verify.return_value = {'error_message': 'error in authentication'}
120
- response = self.client.post(
121
- '/test_company/query',
122
- json=self.test_data
123
- )
124
-
125
- assert response.status_code == 401
126
- assert response.json["error_message"] == 'error in authentication'
127
-
128
-
129
- def test_post_service_error(self):
130
- """Prueba el manejo de errores del servicio."""
131
- self.query_service.llm_query.return_value = {
132
- "error": True,
133
- "error_message": "Error de proceso"
134
- }
135
-
136
- response = self.client.post(
137
- '/test_company/query',
138
- json=self.test_data
139
- )
140
-
141
- assert response.status_code == 401
142
- assert response.json["error_message"] == "Error de proceso"
143
-
144
- @patch("iatoolkit.views.llmquery_view.render_template")
145
- def test_post_unexpected_error(self, mock_render):
146
- self.query_service.llm_query.side_effect = Exception("Error inesperado")
147
-
148
- test_data = {
149
- "question": "¿Pregunta con error?",
150
- "files": []
151
- }
152
-
153
- response = self.client.post('/test_company/query',json=test_data)
154
- assert response.status_code == 500
@@ -1,114 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Product: IAToolkit
3
- #
4
- # IAToolkit is open source software.
5
-
6
- import pytest
7
- from flask import Flask, jsonify
8
- from unittest.mock import MagicMock, patch
9
- from iatoolkit.services.profile_service import ProfileService
10
- from iatoolkit.views.login_view import LoginView
11
- from iatoolkit.repositories.models import Company
12
-
13
-
14
- class TestLoginView:
15
- @staticmethod
16
- def create_app():
17
- """Configura la aplicación Flask para pruebas."""
18
- app = Flask(__name__)
19
- app.testing = True
20
-
21
- return app
22
-
23
- @pytest.fixture(autouse=True)
24
- def setup(self):
25
- """Configura el cliente y el mock antes de cada test."""
26
- self.app = self.create_app()
27
- self.client = self.app.test_client()
28
- self.profile_service = MagicMock(spec=ProfileService)
29
- self.test_company = Company(
30
- id=1,
31
- name="Empresa de Prueba",
32
- short_name="test_company",
33
- logo_file="test_logo.png"
34
- )
35
- self.profile_service.get_company_by_short_name.return_value = self.test_company
36
-
37
- # Registrar la vista
38
- view = LoginView.as_view("login", profile_service=self.profile_service)
39
- self.app.add_url_rule("/<company_short_name>/login", view_func=view, methods=["GET", "POST"])
40
-
41
- # Registrar un endpoint temporal para el test
42
- @self.app.route("/test_company/chat")
43
- def chat():
44
- return jsonify({"message": "Bienvenido al chat"}), 200
45
-
46
- @patch("iatoolkit.views.login_view.render_template")
47
- def test_get_and_post_invalid_company(self, mock_render):
48
- self.profile_service.get_company_by_short_name.return_value = None
49
- response = self.client.get("/test_company/login")
50
- assert response.status_code == 404
51
-
52
- response = self.client.post("/test_company/login",
53
- data={"email": "fer", "password": "123456"},
54
- content_type="application/x-www-form-urlencoded")
55
-
56
- assert response.status_code == 404
57
-
58
- @patch("iatoolkit.views.login_view.render_template")
59
- def test_get_login_page(self, mock_render_template):
60
- mock_render_template.return_value = "<html><body><h1>Login Page</h1></body></html>"
61
- response = self.client.get("/test_company/login")
62
-
63
- mock_render_template.assert_called_once_with(
64
- "login.html",
65
- company=self.test_company,
66
- company_short_name='test_company'
67
- )
68
-
69
- assert response.status_code == 200
70
- assert b"<h1>Login Page</h1>" in response.data
71
-
72
- @patch("iatoolkit.views.login_view.render_template")
73
- def test_post_with_error(self, mock_render_template):
74
- self.profile_service.login.return_value = {'error': 'login error'}
75
- mock_render_template.return_value = "<html><body><h1>Login Page</h1></body></html>"
76
- response = self.client.post("/test_company/login",
77
- data={"email": "fer", "password": "123456"},
78
- content_type="application/x-www-form-urlencoded")
79
-
80
- mock_render_template.assert_called_once_with(
81
- "login.html",
82
- company=self.test_company,
83
- company_short_name='test_company',
84
- form_data={"email": "fer", "password": "123456"},
85
- alert_message='login error'
86
- )
87
- assert response.status_code == 400
88
-
89
- def test_post_successful_login(self):
90
- self.profile_service.login.return_value = {"message": "Login exitoso"}
91
- response = self.client.post("/test_company/login",
92
- data={"email": "test@email.com", "password": "password"},
93
- content_type="application/x-www-form-urlencoded")
94
-
95
- assert response.status_code == 302 # Redirección exitosa
96
- assert response.location == "/test_company/chat?company_short_name=test_company"
97
-
98
-
99
- @patch("iatoolkit.views.login_view.render_template")
100
- def test_post_unexpected_error(self, mock_render_template):
101
- """Prueba que se maneje correctamente un error inesperado."""
102
- self.profile_service.login.side_effect = Exception("Unexpected error")
103
- mock_render_template.return_value = "<html><body><h1>Error Page</h1></body></html>"
104
- response = self.client.post("/test_company/login",
105
- data={"email": "test@mail.com", "password": "any"},
106
- content_type="application/x-www-form-urlencoded")
107
-
108
- mock_render_template.assert_called_once_with(
109
- "error.html",
110
- company=self.test_company,
111
- company_short_name='test_company',
112
- message="Ha ocurrido un error inesperado."
113
- )
114
- assert response.status_code == 500