dmart 0.1.9__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.
- alembic/__init__.py +0 -0
- alembic/env.py +91 -0
- alembic/scripts/__init__.py +0 -0
- alembic/scripts/calculate_checksums.py +77 -0
- alembic/scripts/migration_f7a4949eed19.py +28 -0
- alembic/versions/0f3d2b1a7c21_add_authz_materialized_views.py +87 -0
- alembic/versions/10d2041b94d4_last_checksum_history.py +62 -0
- alembic/versions/1cf4e1ee3cb8_ext_permission_with_filter_fields_values.py +33 -0
- alembic/versions/26bfe19b49d4_rm_failedloginattempts.py +42 -0
- alembic/versions/3c8bca2219cc_add_otp_table.py +38 -0
- alembic/versions/6675fd9dfe42_remove_unique_from_sessions_table.py +36 -0
- alembic/versions/71bc1df82e6a_adding_user_last_login_at.py +43 -0
- alembic/versions/74288ccbd3b5_initial.py +264 -0
- alembic/versions/7520a89a8467_rm_activesession_table.py +39 -0
- alembic/versions/848b623755a4_make_created_nd_updated_at_required.py +138 -0
- alembic/versions/8640dcbebf85_add_notes_to_users.py +32 -0
- alembic/versions/91c94250232a_adding_fk_on_owner_shortname.py +104 -0
- alembic/versions/98ecd6f56f9a_ext_meta_with_owner_group_shortname.py +66 -0
- alembic/versions/9aae9138c4ef_indexing_created_at_updated_at.py +80 -0
- alembic/versions/__init__.py +0 -0
- alembic/versions/b53f916b3f6d_json_to_jsonb.py +492 -0
- alembic/versions/eb5f1ec65156_adding_user_locked_to_device.py +36 -0
- alembic/versions/f7a4949eed19_adding_query_policies_to_meta.py +60 -0
- api/__init__.py +0 -0
- api/info/__init__.py +0 -0
- api/info/router.py +109 -0
- api/managed/__init__.py +0 -0
- api/managed/router.py +1541 -0
- api/managed/utils.py +1850 -0
- api/public/__init__.py +0 -0
- api/public/router.py +758 -0
- api/qr/__init__.py +0 -0
- api/qr/router.py +108 -0
- api/user/__init__.py +0 -0
- api/user/model/__init__.py +0 -0
- api/user/model/errors.py +14 -0
- api/user/model/requests.py +165 -0
- api/user/model/responses.py +11 -0
- api/user/router.py +1401 -0
- api/user/service.py +270 -0
- bundler.py +44 -0
- config/__init__.py +0 -0
- config/channels.json +11 -0
- config/notification.json +17 -0
- data_adapters/__init__.py +0 -0
- data_adapters/adapter.py +16 -0
- data_adapters/base_data_adapter.py +467 -0
- data_adapters/file/__init__.py +0 -0
- data_adapters/file/adapter.py +2043 -0
- data_adapters/file/adapter_helpers.py +1013 -0
- data_adapters/file/archive.py +150 -0
- data_adapters/file/create_index.py +331 -0
- data_adapters/file/create_users_folders.py +52 -0
- data_adapters/file/custom_validations.py +68 -0
- data_adapters/file/drop_index.py +40 -0
- data_adapters/file/health_check.py +560 -0
- data_adapters/file/redis_services.py +1110 -0
- data_adapters/helpers.py +27 -0
- data_adapters/sql/__init__.py +0 -0
- data_adapters/sql/adapter.py +3210 -0
- data_adapters/sql/adapter_helpers.py +491 -0
- data_adapters/sql/create_tables.py +451 -0
- data_adapters/sql/create_users_folders.py +53 -0
- data_adapters/sql/db_to_json_migration.py +482 -0
- data_adapters/sql/health_check_sql.py +232 -0
- data_adapters/sql/json_to_db_migration.py +454 -0
- data_adapters/sql/update_query_policies.py +101 -0
- data_generator.py +81 -0
- dmart-0.1.9.dist-info/METADATA +64 -0
- dmart-0.1.9.dist-info/RECORD +149 -0
- dmart-0.1.9.dist-info/WHEEL +5 -0
- dmart-0.1.9.dist-info/entry_points.txt +2 -0
- dmart-0.1.9.dist-info/top_level.txt +23 -0
- dmart.py +513 -0
- get_settings.py +7 -0
- languages/__init__.py +0 -0
- languages/arabic.json +15 -0
- languages/english.json +16 -0
- languages/kurdish.json +14 -0
- languages/loader.py +13 -0
- main.py +506 -0
- migrate.py +24 -0
- models/__init__.py +0 -0
- models/api.py +203 -0
- models/core.py +597 -0
- models/enums.py +255 -0
- password_gen.py +8 -0
- plugins/__init__.py +0 -0
- plugins/action_log/__init__.py +0 -0
- plugins/action_log/plugin.py +121 -0
- plugins/admin_notification_sender/__init__.py +0 -0
- plugins/admin_notification_sender/plugin.py +124 -0
- plugins/ldap_manager/__init__.py +0 -0
- plugins/ldap_manager/plugin.py +100 -0
- plugins/local_notification/__init__.py +0 -0
- plugins/local_notification/plugin.py +123 -0
- plugins/realtime_updates_notifier/__init__.py +0 -0
- plugins/realtime_updates_notifier/plugin.py +58 -0
- plugins/redis_db_update/__init__.py +0 -0
- plugins/redis_db_update/plugin.py +188 -0
- plugins/resource_folders_creation/__init__.py +0 -0
- plugins/resource_folders_creation/plugin.py +81 -0
- plugins/system_notification_sender/__init__.py +0 -0
- plugins/system_notification_sender/plugin.py +188 -0
- plugins/update_access_controls/__init__.py +0 -0
- plugins/update_access_controls/plugin.py +9 -0
- pytests/__init__.py +0 -0
- pytests/api_user_models_erros_test.py +16 -0
- pytests/api_user_models_requests_test.py +98 -0
- pytests/archive_test.py +72 -0
- pytests/base_test.py +300 -0
- pytests/get_settings_test.py +14 -0
- pytests/json_to_db_migration_test.py +237 -0
- pytests/service_test.py +26 -0
- pytests/test_info.py +55 -0
- pytests/test_status.py +15 -0
- run_notification_campaign.py +98 -0
- scheduled_notification_handler.py +121 -0
- schema_migration.py +208 -0
- schema_modulate.py +192 -0
- set_admin_passwd.py +55 -0
- sync.py +202 -0
- utils/__init__.py +0 -0
- utils/access_control.py +306 -0
- utils/async_request.py +8 -0
- utils/exporter.py +309 -0
- utils/firebase_notifier.py +57 -0
- utils/generate_email.py +38 -0
- utils/helpers.py +352 -0
- utils/hypercorn_config.py +12 -0
- utils/internal_error_code.py +60 -0
- utils/jwt.py +124 -0
- utils/logger.py +167 -0
- utils/middleware.py +99 -0
- utils/notification.py +75 -0
- utils/password_hashing.py +16 -0
- utils/plugin_manager.py +215 -0
- utils/query_policies_helper.py +112 -0
- utils/regex.py +44 -0
- utils/repository.py +529 -0
- utils/router_helper.py +19 -0
- utils/settings.py +165 -0
- utils/sms_notifier.py +21 -0
- utils/social_sso.py +67 -0
- utils/templates/activation.html.j2 +26 -0
- utils/templates/reminder.html.j2 +17 -0
- utils/ticket_sys_utils.py +203 -0
- utils/web_notifier.py +29 -0
- websocket.py +231 -0
api/user/service.py
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import random
|
|
3
|
+
import string
|
|
4
|
+
import time
|
|
5
|
+
from data_adapters.adapter import data_adapter as db
|
|
6
|
+
from models import core
|
|
7
|
+
from models.api import Error, Exception
|
|
8
|
+
from models.enums import ContentType
|
|
9
|
+
from utils import password_hashing
|
|
10
|
+
from utils.async_request import AsyncRequest
|
|
11
|
+
from utils.internal_error_code import InternalErrorCode
|
|
12
|
+
from utils.settings import settings
|
|
13
|
+
from fastapi.logger import logger
|
|
14
|
+
from fastapi import status
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
MANAGEMENT_SPACE: str = settings.management_space
|
|
18
|
+
USERS_SUBPATH: str = "users"
|
|
19
|
+
|
|
20
|
+
path = f"{os.path.dirname(__file__)}/mocks/"
|
|
21
|
+
|
|
22
|
+
headers = {"Content-Type": "application/json", "auth-key": settings.smpp_auth_key}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def gen_alphanumeric(length=16):
|
|
26
|
+
return "".join(
|
|
27
|
+
random.choice(string.ascii_letters + string.digits) for _ in range(length)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def gen_numeric(length=6):
|
|
32
|
+
return "".join(random.choice(string.digits) for _ in range(length))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def mock_sending_otp(msisdn) -> dict:
|
|
36
|
+
key = f"users:otp:otps/{msisdn}"
|
|
37
|
+
await db.save_otp(key, settings.mock_otp_code)
|
|
38
|
+
json = {"status": "success", "data": {"status": "success"}}
|
|
39
|
+
return json
|
|
40
|
+
|
|
41
|
+
def get_otp_key(user_identifier: dict[str, str]) -> str:
|
|
42
|
+
if "msisdn" in user_identifier:
|
|
43
|
+
return f"users:otp:otps/{user_identifier['msisdn']}"
|
|
44
|
+
elif "email" in user_identifier:
|
|
45
|
+
return f"users:otp:otps/{user_identifier['email']}"
|
|
46
|
+
return ""
|
|
47
|
+
|
|
48
|
+
async def send_otp(msisdn: str, language: str):
|
|
49
|
+
json = {}
|
|
50
|
+
status: int
|
|
51
|
+
if settings.mock_smpp_api:
|
|
52
|
+
return await mock_sending_otp(msisdn)
|
|
53
|
+
|
|
54
|
+
# Creating SMS message body
|
|
55
|
+
code = gen_numeric()
|
|
56
|
+
message = ""
|
|
57
|
+
match language:
|
|
58
|
+
case "ckb":
|
|
59
|
+
message = f"کۆدی دڵنیابوونی تایبەت بەخۆت {code}"
|
|
60
|
+
case "en":
|
|
61
|
+
message = f"Your otp code is {code}"
|
|
62
|
+
case _:
|
|
63
|
+
message = f"رمز التحقق الخاص بك {code}"
|
|
64
|
+
|
|
65
|
+
await db.save_otp(f"users:otp:otps/{msisdn}", code)
|
|
66
|
+
|
|
67
|
+
async with AsyncRequest() as client:
|
|
68
|
+
response = await client.post(
|
|
69
|
+
settings.send_sms_otp_api,
|
|
70
|
+
headers={**headers, "skel-accept-language": language},
|
|
71
|
+
json={"msisdn": msisdn, "text": message},
|
|
72
|
+
)
|
|
73
|
+
json = await response.json()
|
|
74
|
+
status = response.status
|
|
75
|
+
|
|
76
|
+
if status != 200:
|
|
77
|
+
raise Exception(
|
|
78
|
+
status, Error(type="otp", code=InternalErrorCode.OTP_ISSUE, message="OTP issue", info=[json])
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return json.get("data")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
async def email_send_otp(email: str, language: str):
|
|
85
|
+
if settings.mock_smtp_api:
|
|
86
|
+
return await mock_sending_otp(email)
|
|
87
|
+
|
|
88
|
+
code = "".join(random.choice("0123456789") for _ in range(6))
|
|
89
|
+
await db.save_otp(f"users:otp:otps/{email}", code)
|
|
90
|
+
message = f"<p>Your OTP code is <b>{code}</b></p>"
|
|
91
|
+
return await send_email(settings.email_sender, email, message, "OTP", settings.send_email_otp_api)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
async def send_sms(msisdn: str, message: str) -> bool:
|
|
95
|
+
json = {}
|
|
96
|
+
status: int
|
|
97
|
+
if settings.mock_smpp_api:
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
async with AsyncRequest() as client:
|
|
101
|
+
response = await client.post(
|
|
102
|
+
settings.send_sms_api,
|
|
103
|
+
headers={**headers},
|
|
104
|
+
json={"msisdn": msisdn, "text": message},
|
|
105
|
+
)
|
|
106
|
+
json = await response.json()
|
|
107
|
+
status = response.status
|
|
108
|
+
|
|
109
|
+
if status != 200:
|
|
110
|
+
logger.warning(
|
|
111
|
+
"sms_sender_exception",
|
|
112
|
+
extra={
|
|
113
|
+
"props": {
|
|
114
|
+
"status": status,
|
|
115
|
+
"response": json,
|
|
116
|
+
"target": msisdn
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
)
|
|
120
|
+
return False
|
|
121
|
+
|
|
122
|
+
return True
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
async def send_email(from_address: str, to_address: str, message: str, subject: str, send_email_api=settings.send_email_api) -> bool:
|
|
126
|
+
json = {}
|
|
127
|
+
status: int
|
|
128
|
+
start_time = time.time()
|
|
129
|
+
if settings.mock_smtp_api:
|
|
130
|
+
return True
|
|
131
|
+
|
|
132
|
+
async with AsyncRequest() as client:
|
|
133
|
+
response = await client.post(
|
|
134
|
+
send_email_api,
|
|
135
|
+
headers={**headers},
|
|
136
|
+
json={
|
|
137
|
+
"from_address": from_address,
|
|
138
|
+
"to": to_address,
|
|
139
|
+
"msg": message,
|
|
140
|
+
"subject": subject,
|
|
141
|
+
},
|
|
142
|
+
)
|
|
143
|
+
json = await response.json()
|
|
144
|
+
status = response.status
|
|
145
|
+
logger.info(
|
|
146
|
+
"Email Service",
|
|
147
|
+
extra={
|
|
148
|
+
"props": {
|
|
149
|
+
"duration": 1000 * (time.time() - start_time),
|
|
150
|
+
"request": {
|
|
151
|
+
"from_address": from_address,
|
|
152
|
+
"to": to_address,
|
|
153
|
+
"msg": message,
|
|
154
|
+
},
|
|
155
|
+
"response": {"status": status, "json": json},
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
if status != 200:
|
|
161
|
+
logger.warning(
|
|
162
|
+
"Email Service",
|
|
163
|
+
extra={
|
|
164
|
+
"props": {
|
|
165
|
+
"status": status,
|
|
166
|
+
"response": json,
|
|
167
|
+
"target": to_address,
|
|
168
|
+
"sender": from_address
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
)
|
|
172
|
+
return False
|
|
173
|
+
|
|
174
|
+
return True
|
|
175
|
+
|
|
176
|
+
async def get_shortname_from_identifier(key, value):
|
|
177
|
+
if isinstance(value, str) and isinstance(key, str):
|
|
178
|
+
shortname = await db.get_user_by_criteria(key, value)
|
|
179
|
+
if shortname is None:
|
|
180
|
+
raise Exception(
|
|
181
|
+
status.HTTP_404_NOT_FOUND,
|
|
182
|
+
Error(
|
|
183
|
+
type="auth",
|
|
184
|
+
code=InternalErrorCode.SHORTNAME_DOES_NOT_EXIST,
|
|
185
|
+
message="User not found",
|
|
186
|
+
)
|
|
187
|
+
)
|
|
188
|
+
if not (await db.is_user_verified(shortname, key)):
|
|
189
|
+
raise Exception(
|
|
190
|
+
status.HTTP_401_UNAUTHORIZED,
|
|
191
|
+
Error(
|
|
192
|
+
type="auth",
|
|
193
|
+
code=InternalErrorCode.USER_ISNT_VERIFIED,
|
|
194
|
+
message="This user is not verified",
|
|
195
|
+
),
|
|
196
|
+
)
|
|
197
|
+
return shortname
|
|
198
|
+
else:
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def check_user_validation(user, data, user_updates, invitation_token):
|
|
203
|
+
if (
|
|
204
|
+
data.get("channel") == "EMAIL"
|
|
205
|
+
and user.email
|
|
206
|
+
and f"EMAIL:{user.email}" in invitation_token
|
|
207
|
+
):
|
|
208
|
+
user_updates["is_email_verified"] = True
|
|
209
|
+
elif (
|
|
210
|
+
data.get("channel") == "SMS"
|
|
211
|
+
and user.msisdn
|
|
212
|
+
and f"SMS:{user.msisdn}" in invitation_token
|
|
213
|
+
):
|
|
214
|
+
user_updates["is_msisdn_verified"] = True
|
|
215
|
+
|
|
216
|
+
return user_updates
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
async def set_user_profile(profile, profile_user, user):
|
|
220
|
+
if profile_user.password:
|
|
221
|
+
user.password = password_hashing.hash_password(profile_user.password)
|
|
222
|
+
user.force_password_change = False
|
|
223
|
+
# Clear the failed password attempts
|
|
224
|
+
await db.clear_failed_password_attempts(profile.shortname)
|
|
225
|
+
if "displayname" in profile.attributes:
|
|
226
|
+
user.displayname = profile_user.displayname.model_dump()
|
|
227
|
+
if "description" in profile.attributes:
|
|
228
|
+
user.description = profile_user.description.model_dump()
|
|
229
|
+
if "language" in profile.attributes:
|
|
230
|
+
user.language = profile_user.language
|
|
231
|
+
if "is_active" in profile.attributes:
|
|
232
|
+
user.is_active = profile_user.is_active
|
|
233
|
+
return user
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
async def get_otp_confirmation_email_or_msisdn(profile_user):
|
|
237
|
+
if profile_user.email:
|
|
238
|
+
return await db.get_otp(f"users:otp:confirmation/email/{profile_user.email}")
|
|
239
|
+
elif profile_user.msisdn:
|
|
240
|
+
return await db.get_otp(f"users:otp:confirmation/msisdn/{profile_user.msisdn}")
|
|
241
|
+
return None
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
async def update_user_payload(profile, profile_user, user, shortname):
|
|
245
|
+
separate_payload_data = {}
|
|
246
|
+
user.payload = core.Payload(
|
|
247
|
+
content_type=ContentType.json,
|
|
248
|
+
schema_shortname=profile_user.payload.schema_shortname,
|
|
249
|
+
body="",
|
|
250
|
+
)
|
|
251
|
+
if profile.attributes["payload"]["body"]:
|
|
252
|
+
separate_payload_data = profile.attributes["payload"]["body"]
|
|
253
|
+
if settings.active_data_db == "file":
|
|
254
|
+
user.payload.body = f"{shortname}.json"
|
|
255
|
+
|
|
256
|
+
if user.payload and separate_payload_data:
|
|
257
|
+
if profile_user.payload.schema_shortname:
|
|
258
|
+
await db.validate_payload_with_schema(
|
|
259
|
+
payload_data=separate_payload_data,
|
|
260
|
+
space_name=MANAGEMENT_SPACE,
|
|
261
|
+
schema_shortname=str(user.payload.schema_shortname),
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
await db.save_payload_from_json(
|
|
265
|
+
MANAGEMENT_SPACE,
|
|
266
|
+
USERS_SUBPATH,
|
|
267
|
+
user,
|
|
268
|
+
separate_payload_data,
|
|
269
|
+
)
|
|
270
|
+
|
bundler.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env -S BACKEND_ENV=config.env python3
|
|
2
|
+
import json
|
|
3
|
+
import subprocess
|
|
4
|
+
import PyInstaller.__main__
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
branch_cmd = "git rev-parse --abbrev-ref HEAD"
|
|
8
|
+
result, _ = subprocess.Popen(branch_cmd.split(" "), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
|
9
|
+
branch = None if result is None or len(result) == 0 else result.decode().strip()
|
|
10
|
+
|
|
11
|
+
version_cmd = "git rev-parse --short HEAD"
|
|
12
|
+
result, _ = subprocess.Popen(version_cmd.split(" "), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
|
13
|
+
version = None if result is None or len(result) == 0 else result.decode().strip()
|
|
14
|
+
|
|
15
|
+
tag_cmd = "git describe --tags"
|
|
16
|
+
result, _ = subprocess.Popen(tag_cmd.split(" "), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
|
17
|
+
tag = None if result is None or len(result) == 0 else result.decode().strip()
|
|
18
|
+
|
|
19
|
+
version_date_cmd = "git show --pretty=format:'%ad'"
|
|
20
|
+
result, _ = subprocess.Popen(version_date_cmd.split(" "), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
|
21
|
+
version_date = None if result is None or len(result) == 0 else result.decode().split("\n")[0]
|
|
22
|
+
|
|
23
|
+
info = {
|
|
24
|
+
"branch": branch,
|
|
25
|
+
"version": version,
|
|
26
|
+
"tag": tag,
|
|
27
|
+
"version_date": version_date
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
json.dump(info, open('info.json', 'w'))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
PyInstaller.__main__.run([
|
|
34
|
+
'dmart.py',
|
|
35
|
+
'--name=dmart',
|
|
36
|
+
'--onefile',
|
|
37
|
+
'--runtime-tmpdir=.',
|
|
38
|
+
'--distpath=.',
|
|
39
|
+
'--add-data=./info.json:.',
|
|
40
|
+
'--noconfirm',
|
|
41
|
+
'--collect-submodules=concurrent_log_handler',
|
|
42
|
+
'--collect-submodules=pythonjsonlogger',
|
|
43
|
+
'--clean',
|
|
44
|
+
])
|
config/__init__.py
ADDED
|
File without changes
|
config/channels.json
ADDED
config/notification.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"web": {
|
|
3
|
+
"active": true,
|
|
4
|
+
"module": "utils.web_notifier",
|
|
5
|
+
"class": "WebNotifier"
|
|
6
|
+
},
|
|
7
|
+
"sms": {
|
|
8
|
+
"active": true,
|
|
9
|
+
"module": "utils.sms_notifier",
|
|
10
|
+
"class": "SMSNotifier"
|
|
11
|
+
},
|
|
12
|
+
"mobile": {
|
|
13
|
+
"active": true,
|
|
14
|
+
"module": "utils.firebase_notifier",
|
|
15
|
+
"class": "FirebaseNotifier"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
File without changes
|
data_adapters/adapter.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Type
|
|
2
|
+
|
|
3
|
+
from .base_data_adapter import BaseDataAdapter
|
|
4
|
+
from .file.adapter import FileAdapter
|
|
5
|
+
from .sql.adapter import SQLAdapter
|
|
6
|
+
from utils.settings import settings
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
AVAILABLE_DATA_REPOSITORIES: dict[str, Type[SQLAdapter | FileAdapter]] = {
|
|
10
|
+
'file': FileAdapter,
|
|
11
|
+
'sql': SQLAdapter
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
data_adapter: BaseDataAdapter = AVAILABLE_DATA_REPOSITORIES[settings.active_data_db]()
|
|
15
|
+
|
|
16
|
+
# asyncio.run(data_adapter.test_connection())
|