iatoolkit 0.67.0__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.

Files changed (37) hide show
  1. iatoolkit/__init__.py +0 -4
  2. iatoolkit/base_company.py +0 -6
  3. iatoolkit/iatoolkit.py +2 -5
  4. iatoolkit/repositories/database_manager.py +5 -0
  5. iatoolkit/repositories/models.py +0 -2
  6. iatoolkit/services/branding_service.py +7 -5
  7. iatoolkit/services/company_context_service.py +145 -0
  8. iatoolkit/services/configuration_service.py +13 -20
  9. iatoolkit/services/dispatcher_service.py +34 -33
  10. iatoolkit/services/language_service.py +9 -5
  11. iatoolkit/services/profile_service.py +3 -0
  12. iatoolkit/services/query_service.py +4 -1
  13. iatoolkit/services/search_service.py +11 -4
  14. iatoolkit/services/sql_service.py +49 -23
  15. iatoolkit/static/js/chat_onboarding_button.js +6 -0
  16. iatoolkit/static/styles/onboarding.css +7 -0
  17. iatoolkit/templates/change_password.html +1 -1
  18. iatoolkit/templates/chat.html +1 -0
  19. iatoolkit/templates/chat_modals.html +1 -0
  20. iatoolkit/templates/login_simulation.html +1 -1
  21. iatoolkit/templates/onboarding_shell.html +4 -1
  22. iatoolkit/views/base_login_view.py +7 -8
  23. iatoolkit/views/change_password_view.py +2 -3
  24. iatoolkit/views/external_login_view.py +1 -1
  25. iatoolkit/views/forgot_password_view.py +2 -4
  26. iatoolkit/views/help_content_api_view.py +1 -1
  27. iatoolkit/views/home_view.py +1 -2
  28. iatoolkit/views/login_simulation_view.py +1 -1
  29. iatoolkit/views/login_view.py +8 -8
  30. iatoolkit/views/signup_view.py +2 -4
  31. iatoolkit/views/verify_user_view.py +1 -3
  32. {iatoolkit-0.67.0.dist-info → iatoolkit-0.69.0.dist-info}/METADATA +1 -1
  33. {iatoolkit-0.67.0.dist-info → iatoolkit-0.69.0.dist-info}/RECORD +36 -36
  34. iatoolkit/services/onboarding_service.py +0 -49
  35. {iatoolkit-0.67.0.dist-info → iatoolkit-0.69.0.dist-info}/WHEEL +0 -0
  36. {iatoolkit-0.67.0.dist-info → iatoolkit-0.69.0.dist-info}/licenses/LICENSE +0 -0
  37. {iatoolkit-0.67.0.dist-info → iatoolkit-0.69.0.dist-info}/top_level.txt +0 -0
@@ -4,16 +4,22 @@
4
4
  # IAToolkit is open source software.
5
5
 
6
6
  from iatoolkit.repositories.database_manager import DatabaseManager
7
-
8
7
  from iatoolkit.common.util import Utility
9
8
  from iatoolkit.services.i18n_service import I18nService
9
+ from iatoolkit.common.exceptions import IAToolkitException
10
10
  from sqlalchemy import text
11
- from injector import inject
11
+ from injector import inject, singleton
12
12
  import json
13
- from iatoolkit.common.exceptions import IAToolkitException
13
+ import logging
14
14
 
15
15
 
16
+ @singleton
16
17
  class SqlService:
18
+ """
19
+ Manages database connections and executes SQL statements.
20
+ It maintains a cache of named DatabaseManager instances to avoid reconnecting.
21
+ """
22
+
17
23
  @inject
18
24
  def __init__(self,
19
25
  util: Utility,
@@ -21,44 +27,64 @@ class SqlService:
21
27
  self.util = util
22
28
  self.i18n_service = i18n_service
23
29
 
24
- def exec_sql(self, db_manager: DatabaseManager, sql_statement: str) -> str:
30
+ # Cache for database connections
31
+ self._db_connections: dict[str, DatabaseManager] = {}
32
+
33
+ def register_database(self, db_name: str, db_uri: str):
34
+ """
35
+ Creates and caches a DatabaseManager instance for a given database name and URI.
36
+ If a database with the same name is already registered, it does nothing.
25
37
  """
26
- Executes a raw SQL statement and returns the result as a JSON string.
38
+ if db_name in self._db_connections:
39
+ return
27
40
 
28
- This method takes a DatabaseManager instance and a SQL query, executes it
29
- against the database, and fetches all results. The results are converted
30
- into a list of dictionaries, where each dictionary represents a row.
31
- This list is then serialized to a JSON string.
32
- If an exception occurs during execution, the transaction is rolled back,
33
- and a custom IAToolkitException is raised.
41
+ logging.debug(f"Registering and creating connection for database: '{db_name}'")
42
+ db_manager = DatabaseManager(db_uri, register_pgvector=False)
43
+ self._db_connections[db_name] = db_manager
34
44
 
35
- Args:
36
- db_manager: The DatabaseManager instance to get the database session from.
37
- sql_statement: The raw SQL statement to be executed.
45
+ def get_database_manager(self, db_name: str) -> DatabaseManager:
46
+ """
47
+ Retrieves a registered DatabaseManager instance from the cache.
48
+ """
49
+ try:
50
+ return self._db_connections[db_name]
51
+ except KeyError:
52
+ logging.error(f"Attempted to access unregistered database: '{db_name}'")
53
+ raise IAToolkitException(
54
+ IAToolkitException.ErrorType.DATABASE_ERROR,
55
+ f"Database '{db_name}' is not registered with the SqlService."
56
+ )
38
57
 
39
- Returns:
40
- A JSON string representing the list of rows returned by the query.
58
+ def exec_sql(self, db_name: str, sql_statement: str) -> str:
59
+ """
60
+ Executes a raw SQL statement against a registered database and returns the result as a JSON string.
41
61
  """
42
62
  try:
43
- # here the SQL is executed
44
- result = db_manager.get_session().execute(text(sql_statement))
63
+ # 1. Get the database manager from the cache
64
+ db_manager = self.get_database_manager(db_name)
45
65
 
46
- # get the column names
66
+ # 2. Execute the SQL statement
67
+ result = db_manager.get_session().execute(text(sql_statement))
47
68
  cols = result.keys()
48
-
49
- # convert rows to dict
50
69
  rows_context = [dict(zip(cols, row)) for row in result.fetchall()]
51
70
 
52
- # Serialize to JSON with type convertion
71
+ # seialize the result
53
72
  sql_result_json = json.dumps(rows_context, default=self.util.serialize)
54
73
 
55
74
  return sql_result_json
75
+ except IAToolkitException:
76
+ # Re-raise exceptions from get_database_manager to preserve the specific error
77
+ raise
56
78
  except Exception as e:
57
- db_manager.get_session().rollback()
79
+ # Attempt to rollback if a session was active
80
+ db_manager = self._db_connections.get(db_name)
81
+ if db_manager:
82
+ db_manager.get_session().rollback()
58
83
 
59
84
  error_message = str(e)
60
85
  if 'timed out' in str(e):
61
86
  error_message = self.i18n_service.t('errors.timeout')
62
87
 
88
+ logging.error(f"Error executing SQL statement: {error_message}")
63
89
  raise IAToolkitException(IAToolkitException.ErrorType.DATABASE_ERROR,
64
90
  error_message) from e
@@ -28,6 +28,7 @@
28
28
  const elIcon = qs(root, ui.icon);
29
29
  const elTitle = qs(root, ui.title);
30
30
  const elText = qs(root, ui.text);
31
+ const elExample = qs(root, ui.example);
31
32
  const elDots = qs(root, ui.dots);
32
33
  const elPrev = qs(root, ui.prev);
33
34
  const elNext = qs(root, ui.next);
@@ -43,6 +44,11 @@
43
44
  if (elIcon) elIcon.innerHTML = `<i class="${c.icon || 'bi bi-lightbulb'}"></i>`;
44
45
  if (elTitle) elTitle.textContent = c.title || '';
45
46
  if (elText) elText.innerHTML = c.text || '';
47
+ if (elExample && c.example) {
48
+ elExample.innerHTML = ('Ejemplo: ' + c.example) || '';
49
+ }
50
+ else
51
+ elExample.innerHTML = '';
46
52
  if (elDots) createDots(elDots, cards.length, idx);
47
53
  }
48
54
 
@@ -36,6 +36,13 @@
36
36
  min-height: 60px;
37
37
  }
38
38
 
39
+ .ob-example {
40
+ font-size: 0.95rem;
41
+ color: #444;
42
+ line-height: 1.5;
43
+ min-height: 60px;
44
+ }
45
+
39
46
  /* Navegación */
40
47
  .ob-nav {
41
48
  display: flex;
@@ -1,6 +1,6 @@
1
1
  {% extends "base.html" %}
2
2
 
3
- {% block title %}{{ t('ui.change_password.title') }} - {{ company.name }}{% endblock %}
3
+ {% block title %}{{ t('ui.change_password.title') }} - {{ branding.name }} {% endblock %}
4
4
 
5
5
  {% block styles %}
6
6
  <style>
@@ -272,6 +272,7 @@ document.addEventListener('DOMContentLoaded', function () {
272
272
  icon: '#ob-icon',
273
273
  title: '#ob-title',
274
274
  text: '#ob-text',
275
+ example: '#ob-example',
275
276
  dots: '#ob-dots',
276
277
  prev: '#ob-prev',
277
278
  next: '#ob-next'
@@ -114,6 +114,7 @@
114
114
  <div id="ob-icon" class="ob-icon"><i class="bi bi-lightbulb"></i></div>
115
115
  <h6 id="ob-title" class="ob-title"></h6>
116
116
  <div id="ob-text" class="ob-text"></div>
117
+ <div id="ob-example" class="ob-example"></div>
117
118
  <div class="ob-nav">
118
119
  <button id="ob-prev" class="ob-btn" aria-label="Anterior"><i class="bi bi-chevron-left"></i></button>
119
120
  <div id="ob-dots" class="ob-dots"></div>
@@ -1,6 +1,6 @@
1
1
  {% extends "base.html" %}
2
2
 
3
- {% block title %}Prueba de Login para {{ company_short_name }}{% endblock %}
3
+ {% block title %}Login Test - {{ branding.name }}{% endblock %}
4
4
  {% block styles %}
5
5
  <style>
6
6
  {{ branding.css_variables | safe }}
@@ -1,6 +1,6 @@
1
1
  {% extends "base.html" %}
2
2
 
3
- {% block title %}Iniciando {{ branding.name | default('IAToolkit') }} IA...{% endblock %}
3
+ {% block title %}Iniciando {{ branding.name }} IA...{% endblock %}
4
4
 
5
5
  {% block styles %}
6
6
  {% endblock %}
@@ -45,6 +45,8 @@
45
45
  <div id="card-icon" class="ob-icon"><i class="fas fa-lightbulb"></i></div>
46
46
  <h3 id="card-title" class="ob-title">Título de la Tarjeta</h3>
47
47
  <p id="card-text" class="ob-text">Descripción de la tarjeta de capacitación.</p>
48
+ <p id="card-example" class="ob-example"></p>
49
+
48
50
  <div class="ob-nav">
49
51
  <button id="prev-card" class="ob-btn btn-branded-primary" aria-label="Anterior">
50
52
  <i class="fas fa-chevron-left"></i>
@@ -88,6 +90,7 @@
88
90
  icon: '#card-icon',
89
91
  title: '#card-title',
90
92
  text: '#card-text',
93
+ example: '#card-example',
91
94
  dots: '#progress-dots',
92
95
  prev: '#prev-card',
93
96
  next: '#next-card',
@@ -11,7 +11,7 @@ from iatoolkit.services.profile_service import ProfileService
11
11
  from iatoolkit.services.auth_service import AuthService
12
12
  from iatoolkit.services.query_service import QueryService
13
13
  from iatoolkit.services.branding_service import BrandingService
14
- from iatoolkit.services.onboarding_service import OnboardingService
14
+ from iatoolkit.services.configuration_service import ConfigurationService
15
15
  from iatoolkit.services.prompt_manager_service import PromptService
16
16
  from iatoolkit.services.i18n_service import I18nService
17
17
  from iatoolkit.common.util import Utility
@@ -31,7 +31,7 @@ class BaseLoginView(MethodView):
31
31
  jwt_service: JWTService,
32
32
  branding_service: BrandingService,
33
33
  prompt_service: PromptService,
34
- onboarding_service: OnboardingService,
34
+ config_service: ConfigurationService,
35
35
  query_service: QueryService,
36
36
  i18n_service: I18nService,
37
37
  utility: Utility
@@ -41,14 +41,14 @@ class BaseLoginView(MethodView):
41
41
  self.jwt_service = jwt_service
42
42
  self.branding_service = branding_service
43
43
  self.prompt_service = prompt_service
44
- self.onboarding_service = onboarding_service
44
+ self.config_service = config_service
45
45
  self.query_service = query_service
46
46
  self.i18n_service = i18n_service
47
47
  self.utility = utility
48
48
 
49
49
 
50
50
  def _handle_login_path(self,
51
- company: Company,
51
+ company_short_name: str,
52
52
  user_identifier: str,
53
53
  target_url: str,
54
54
  redeem_token: str = None):
@@ -56,13 +56,12 @@ class BaseLoginView(MethodView):
56
56
  Centralized logic to decide between the fast path and the slow path.
57
57
  """
58
58
  # --- Get the company branding and onboarding_cards
59
- branding_data = self.branding_service.get_company_branding(company)
60
- onboarding_cards = self.onboarding_service.get_onboarding_cards(company)
61
- company_short_name = company.short_name
59
+ branding_data = self.branding_service.get_company_branding(company_short_name)
60
+ onboarding_cards = self.config_service.get_configuration(company_short_name, 'onboarding_cards')
62
61
 
63
62
  # this service decides is the context needs to be rebuilt or not
64
63
  prep_result = self.query_service.prepare_context(
65
- company_short_name=company.short_name, user_identifier=user_identifier
64
+ company_short_name=company_short_name, user_identifier=user_identifier
66
65
  )
67
66
 
68
67
  if prep_result.get('rebuild_needed'):
@@ -34,7 +34,7 @@ class ChangePasswordView(MethodView):
34
34
  return render_template('error.html',
35
35
  message=self.i18n_service.t('errors.templates.company_not_found')), 404
36
36
 
37
- branding_data = self.branding_service.get_company_branding(company)
37
+ branding_data = self.branding_service.get_company_branding(company_short_name)
38
38
 
39
39
  try:
40
40
  # Decodificar el token
@@ -66,7 +66,7 @@ class ChangePasswordView(MethodView):
66
66
  return render_template('error.html',
67
67
  message=self.i18n_service.t('errors.templates.company_not_found')), 404
68
68
 
69
- branding_data = self.branding_service.get_company_branding(company)
69
+ branding_data = self.branding_service.get_company_branding(company_short_name)
70
70
  try:
71
71
  # Decodificar el token
72
72
  email = self.serializer.loads(token, salt='password-reset', max_age=3600)
@@ -98,7 +98,6 @@ class ChangePasswordView(MethodView):
98
98
  'change_password.html',
99
99
  token=token,
100
100
  company_short_name=company_short_name,
101
- company=company,
102
101
  branding=branding_data,
103
102
  form_data={"temp_code": temp_code,
104
103
  "new_password": new_password,
@@ -47,7 +47,7 @@ class ExternalLoginView(BaseLoginView):
47
47
 
48
48
  # 5. Delegate the path decision to the centralized logic.
49
49
  try:
50
- return self._handle_login_path(company, user_identifier, target_url, redeem_token)
50
+ return self._handle_login_path(company_short_name, user_identifier, target_url, redeem_token)
51
51
  except Exception as e:
52
52
  logging.exception(f"Error processing external login path for {company_short_name}/{user_identifier}: {e}")
53
53
  return jsonify({"error": f"Internal server error while starting chat. {str(e)}"}), 500
@@ -30,9 +30,8 @@ class ForgotPasswordView(MethodView):
30
30
  return render_template('error.html',
31
31
  message=self.i18n_service.t('errors.templates.company_not_found')), 404
32
32
 
33
- branding_data = self.branding_service.get_company_branding(company)
33
+ branding_data = self.branding_service.get_company_branding(company_short_name)
34
34
  return render_template('forgot_password.html',
35
- company=company,
36
35
  company_short_name=company_short_name,
37
36
  branding=branding_data
38
37
  )
@@ -45,7 +44,7 @@ class ForgotPasswordView(MethodView):
45
44
  return render_template('error.html',
46
45
  message=self.i18n_service.t('errors.templates.company_not_found')), 404
47
46
 
48
- branding_data = self.branding_service.get_company_branding(company)
47
+ branding_data = self.branding_service.get_company_branding(company_short_name)
49
48
  email = request.form.get('email')
50
49
 
51
50
  # create a safe token and url for it
@@ -59,7 +58,6 @@ class ForgotPasswordView(MethodView):
59
58
  flash(response["error"], 'error')
60
59
  return render_template(
61
60
  'forgot_password.html',
62
- company=company,
63
61
  company_short_name=company_short_name,
64
62
  branding=branding_data,
65
63
  form_data={"email": email}), 400
@@ -37,7 +37,7 @@ class HelpContentApiView(MethodView):
37
37
  user_identifier = auth_result.get('user_identifier')
38
38
 
39
39
  # 2. Call the config service with the unified identifier.
40
- response = self.config_service.get_company_content(
40
+ response = self.config_service.get_configuration(
41
41
  company_short_name=company_short_name,
42
42
  content_key='help_content' # specific key for this service
43
43
  )
@@ -31,7 +31,7 @@ class HomeView(MethodView):
31
31
  return render_template('error.html',
32
32
  message=self.i18n_service.t('errors.templates.company_not_found')), 404
33
33
 
34
- branding_data = self.branding_service.get_company_branding(company)
34
+ branding_data = self.branding_service.get_company_branding(company_short_name)
35
35
  home_template = self.util.get_company_template(company_short_name, "home.html")
36
36
 
37
37
  # 2. Verificamos si el archivo de plantilla personalizado no existe.
@@ -47,7 +47,6 @@ class HomeView(MethodView):
47
47
  # 3. Si el archivo existe, intentamos leerlo y renderizarlo.
48
48
  return render_template_string(
49
49
  home_template,
50
- company=company,
51
50
  company_short_name=company_short_name,
52
51
  branding=branding_data,
53
52
  )
@@ -29,7 +29,7 @@ class LoginSimulationView(MethodView):
29
29
  company_short_name=company_short_name,
30
30
  message="Empresa no encontrada"), 404
31
31
 
32
- branding_data = self.branding_service.get_company_branding(company)
32
+ branding_data = self.branding_service.get_company_branding(company_short_name)
33
33
 
34
34
  return render_template('login_simulation.html',
35
35
  branding=branding_data,
@@ -12,7 +12,7 @@ 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.onboarding_service import OnboardingService
15
+ from iatoolkit.services.configuration_service import ConfigurationService
16
16
  from iatoolkit.services.i18n_service import I18nService
17
17
  from iatoolkit.views.base_login_view import BaseLoginView
18
18
  import logging
@@ -29,7 +29,7 @@ class LoginView(BaseLoginView):
29
29
  return render_template('error.html',
30
30
  message=self.i18n_service.t('errors.templates.company_not_found')), 404
31
31
 
32
- branding_data = self.branding_service.get_company_branding(company)
32
+ branding_data = self.branding_service.get_company_branding(company_short_name)
33
33
  email = request.form.get('email')
34
34
  password = request.form.get('password')
35
35
 
@@ -61,7 +61,7 @@ class LoginView(BaseLoginView):
61
61
 
62
62
  # 2. Delegate the path decision to the centralized logic.
63
63
  try:
64
- return self._handle_login_path(company, user_identifier, target_url)
64
+ return self._handle_login_path(company_short_name, user_identifier, target_url)
65
65
  except Exception as e:
66
66
  message = self.i18n_service.t('errors.templates.processing_error', error=str(e))
67
67
  return render_template(
@@ -83,7 +83,7 @@ class FinalizeContextView(MethodView):
83
83
  query_service: QueryService,
84
84
  prompt_service: PromptService,
85
85
  branding_service: BrandingService,
86
- onboarding_service: OnboardingService,
86
+ config_service: ConfigurationService,
87
87
  jwt_service: JWTService,
88
88
  i18n_service: I18nService
89
89
  ):
@@ -92,7 +92,7 @@ class FinalizeContextView(MethodView):
92
92
  self.query_service = query_service
93
93
  self.prompt_service = prompt_service
94
94
  self.branding_service = branding_service
95
- self.onboarding_service = onboarding_service
95
+ self.config_service = config_service
96
96
  self.i18n_service = i18n_service
97
97
 
98
98
  def get(self, company_short_name: str, token: str = None):
@@ -111,7 +111,7 @@ class FinalizeContextView(MethodView):
111
111
 
112
112
  user_identifier = payload.get('user_identifier')
113
113
  else:
114
- logging.warning("Fallo crítico: missing session information or auth token")
114
+ logging.error("missing session information or auth token")
115
115
  return redirect(url_for('home', company_short_name=company_short_name))
116
116
 
117
117
  company = self.profile_service.get_company_by_short_name(company_short_name)
@@ -119,7 +119,7 @@ class FinalizeContextView(MethodView):
119
119
  return render_template('error.html',
120
120
  company_short_name=company_short_name,
121
121
  message="Empresa no encontrada"), 404
122
- branding_data = self.branding_service.get_company_branding(company)
122
+ branding_data = self.branding_service.get_company_branding(company_short_name)
123
123
 
124
124
  # 2. Finalize the context rebuild (the heavy task).
125
125
  self.query_service.finalize_context_rebuild(
@@ -129,7 +129,7 @@ class FinalizeContextView(MethodView):
129
129
 
130
130
  # 3. render the chat page.
131
131
  prompts = self.prompt_service.get_user_prompts(company_short_name)
132
- onboarding_cards = self.onboarding_service.get_onboarding_cards(company)
132
+ onboarding_cards = self.config_service.get_configuration(company_short_name, 'onboarding_cards')
133
133
 
134
134
  # Get the entire 'js_messages' block in the correct language.
135
135
  js_translations = self.i18n_service.get_translation_block('js_messages')
@@ -32,9 +32,8 @@ class SignupView(MethodView):
32
32
  return render_template('error.html',
33
33
  message=self.i18n_service.t('errors.templates.company_not_found')), 404
34
34
 
35
- branding_data = self.branding_service.get_company_branding(company)
35
+ branding_data = self.branding_service.get_company_branding(company_short_name)
36
36
  return render_template('signup.html',
37
- company=company,
38
37
  company_short_name=company_short_name,
39
38
  branding=branding_data)
40
39
 
@@ -45,7 +44,7 @@ class SignupView(MethodView):
45
44
  return render_template('error.html',
46
45
  message=self.i18n_service.t('errors.templates.company_not_found')), 404
47
46
 
48
- branding_data = self.branding_service.get_company_branding(company)
47
+ branding_data = self.branding_service.get_company_branding(company_short_name)
49
48
 
50
49
  first_name = request.form.get('first_name')
51
50
  last_name = request.form.get('last_name')
@@ -70,7 +69,6 @@ class SignupView(MethodView):
70
69
  flash(response["error"], 'error')
71
70
  return render_template(
72
71
  'signup.html',
73
- company=company,
74
72
  company_short_name=company_short_name,
75
73
  branding=branding_data,
76
74
  form_data={
@@ -32,14 +32,13 @@ class VerifyAccountView(MethodView):
32
32
  return render_template('error.html',
33
33
  message=self.i18n_service.t('errors.templates.company_not_found')), 404
34
34
 
35
- branding_data = self.branding_service.get_company_branding(company)
35
+ branding_data = self.branding_service.get_company_branding(company_short_name)
36
36
  try:
37
37
  # decode the token from the URL
38
38
  email = self.serializer.loads(token, salt='email-confirm', max_age=3600*5)
39
39
  except SignatureExpired:
40
40
  flash(self.i18n_service.t('errors.verification.token_expired'), 'error')
41
41
  return render_template('signup.html',
42
- company=company,
43
42
  company_short_name=company_short_name,
44
43
  branding=branding_data,
45
44
  token=token), 400
@@ -49,7 +48,6 @@ class VerifyAccountView(MethodView):
49
48
  flash(response["error"], 'error')
50
49
  return render_template(
51
50
  'signup.html',
52
- company=company,
53
51
  company_short_name=company_short_name,
54
52
  branding=branding_data,
55
53
  token=token), 400
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 0.67.0
3
+ Version: 0.69.0
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT