243 lines
7.3 KiB
Python
243 lines
7.3 KiB
Python
from components.models.users import (
|
|
AddCredential,
|
|
CredentialPatch,
|
|
Credential,
|
|
User,
|
|
UserAdd,
|
|
UserPatch,
|
|
UserProfile,
|
|
UserProfilePatch,
|
|
UserSession,
|
|
constr,
|
|
validate_call,
|
|
UUID,
|
|
)
|
|
from components.utils import merge_models
|
|
from components.database import *
|
|
from components.cache import buster
|
|
|
|
|
|
def _create_credentials_mapping(credentials: dict):
|
|
user_credentials = dict()
|
|
for c in credentials:
|
|
user_credentials.update({c["id"]: Credential.model_validate(c)})
|
|
return user_credentials
|
|
|
|
|
|
@validate_call
|
|
async def what_id(login: str):
|
|
db_params = evaluate_db_params()
|
|
|
|
async with TinyDB(**db_params) as db:
|
|
user = db.table("users").get(Query().login == login)
|
|
|
|
if user:
|
|
return user["id"]
|
|
else:
|
|
raise ValueError("login", "The provided login name is unknown")
|
|
|
|
|
|
@validate_call
|
|
async def create(data: dict):
|
|
db_params = evaluate_db_params()
|
|
create_user = UserAdd.model_validate(data)
|
|
|
|
async with TinyDB(**db_params) as db:
|
|
if db.table("users").search(Query().login == create_user.login):
|
|
raise ValueError("name", "The provided login name exists")
|
|
insert_data = create_user.model_dump(mode="json")
|
|
db.table("users").insert(insert_data)
|
|
|
|
for user_id in IN_MEMORY_DB["CACHE"]["FORMS"].copy():
|
|
if "users" in IN_MEMORY_DB["CACHE"]["FORMS"][user_id]:
|
|
del IN_MEMORY_DB["CACHE"]["FORMS"][user_id]["users"]
|
|
|
|
return insert_data["id"]
|
|
|
|
|
|
@validate_call
|
|
async def get(user_id: UUID, join_credentials: bool = True):
|
|
db_params = evaluate_db_params()
|
|
system_id = "00000000-0000-0000-0000-000000000000"
|
|
|
|
if not IN_MEMORY_DB["CACHE"]["MODELS"].get(system_id):
|
|
IN_MEMORY_DB["CACHE"]["MODELS"][system_id] = dict()
|
|
|
|
async with TinyDB(**db_params) as db:
|
|
if not str(user_id) in IN_MEMORY_DB["CACHE"]["MODELS"][system_id]:
|
|
print(
|
|
User.model_validate(db.table("users").get(Query().id == str(user_id)))
|
|
)
|
|
IN_MEMORY_DB["CACHE"]["MODELS"][system_id][
|
|
str(user_id)
|
|
] = User.model_validate(db.table("users").get(Query().id == str(user_id)))
|
|
|
|
user = IN_MEMORY_DB["CACHE"]["MODELS"][system_id][str(user_id)].copy()
|
|
|
|
credentials = db.table("credentials").search(
|
|
(Query().id.one_of(user.credentials))
|
|
)
|
|
|
|
if join_credentials:
|
|
user.credentials = _create_credentials_mapping(credentials)
|
|
|
|
return user
|
|
|
|
|
|
@validate_call
|
|
async def delete(user_id: UUID):
|
|
db_params = evaluate_db_params()
|
|
user = await get(user_id=user_id, join_credentials=False)
|
|
|
|
if not user:
|
|
raise ValueError("name", "The provided user does not exist")
|
|
|
|
async with TinyDB(**db_params) as db:
|
|
if len(db.table("users").all()) == 1:
|
|
raise ValueError("name", "Cannot delete last user")
|
|
|
|
db.table("credentials").remove(Query().id.one_of(user.credentials))
|
|
deleted = db.table("users").remove(Query().id == str(user_id))
|
|
buster(user.id)
|
|
return user.id
|
|
|
|
|
|
@validate_call
|
|
async def create_credential(user_id: UUID, data: dict):
|
|
db_params = evaluate_db_params()
|
|
credential = AddCredential.model_validate(data)
|
|
user = await get(user_id=user_id, join_credentials=False)
|
|
if not user:
|
|
raise ValueError("name", "The provided user does not exist")
|
|
|
|
async with TinyDB(**db_params) as db:
|
|
db.table("credentials").insert(credential.model_dump(mode="json"))
|
|
user.credentials.append(credential.id)
|
|
db.table("users").update(
|
|
{"credentials": user.credentials},
|
|
Query().id == str(user_id),
|
|
)
|
|
return credential.id
|
|
|
|
|
|
@validate_call
|
|
async def delete_credential(
|
|
user_id: UUID, hex_id: constr(pattern=r"^[0-9a-fA-F]+$", min_length=2)
|
|
):
|
|
db_params = evaluate_db_params()
|
|
user = await get(user_id=user_id, join_credentials=False)
|
|
|
|
if not user:
|
|
raise ValueError("name", "The provided user does not exist")
|
|
|
|
async with TinyDB(**db_params) as db:
|
|
if hex_id in user.credentials:
|
|
user.credentials.remove(hex_id)
|
|
db.table("credentials").remove(Query().id == hex_id)
|
|
db.table("users").update(
|
|
{"credentials": user.credentials}, Query().id == str(user_id)
|
|
)
|
|
return hex_id
|
|
|
|
|
|
@validate_call
|
|
async def patch(user_id: UUID, data: dict):
|
|
db_params = evaluate_db_params()
|
|
user = await get(user_id=user_id, join_credentials=False)
|
|
|
|
if not user:
|
|
raise ValueError("name", "The provided user does not exist")
|
|
|
|
patch_data = UserPatch.model_validate(data)
|
|
patched_user = merge_models(
|
|
user,
|
|
patch_data,
|
|
exclude_strategies=["exclude_override_none"],
|
|
)
|
|
|
|
async with TinyDB(**db_params) as db:
|
|
if db.table("users").get(
|
|
(Query().login == patched_user.login) & (Query().id != str(user_id))
|
|
):
|
|
raise ValueError("login", "The provided login name exists")
|
|
|
|
orphaned_credentials = [
|
|
c for c in user.credentials if c not in patched_user.credentials
|
|
]
|
|
db.table("users").update(
|
|
patched_user.model_dump(mode="json"),
|
|
Query().id == str(user_id),
|
|
)
|
|
db.table("credentials").remove(Query().id.one_of(orphaned_credentials))
|
|
|
|
buster(user.id)
|
|
return user.id
|
|
|
|
|
|
@validate_call
|
|
async def patch_profile(user_id: UUID, data: dict):
|
|
db_params = evaluate_db_params()
|
|
user = await get(user_id=user_id, join_credentials=False)
|
|
|
|
if not user:
|
|
raise ValueError("name", "The provided user does not exist")
|
|
|
|
patch_data = UserProfilePatch.model_validate(data)
|
|
patched_user_profile = merge_models(
|
|
user.profile, patch_data, exclude_strategies=["exclude_override_none"]
|
|
)
|
|
|
|
async with TinyDB(**db_params) as db:
|
|
db.table("users").update(
|
|
{"profile": patched_user_profile.model_dump(mode="json")},
|
|
Query().id == str(user_id),
|
|
)
|
|
return user_id
|
|
|
|
|
|
@validate_call
|
|
async def patch_credential(
|
|
user_id: UUID, hex_id: constr(pattern=r"^[0-9a-fA-F]+$", min_length=2), data: dict
|
|
):
|
|
db_params = evaluate_db_params()
|
|
user = await get(user_id=user_id, join_credentials=True)
|
|
|
|
if not user:
|
|
raise ValueError("name", "The provided user does not exist")
|
|
|
|
if hex_id not in user.credentials:
|
|
raise ValueError(
|
|
"hex_id",
|
|
"The provided credential ID was not found in user context",
|
|
)
|
|
|
|
patch_data = CredentialPatch.model_validate(data)
|
|
patched_credential = merge_models(
|
|
user.credentials[hex_id],
|
|
patch_data,
|
|
exclude_strategies=["exclude_override_none"],
|
|
)
|
|
|
|
async with TinyDB(**db_params) as db:
|
|
db.table("credentials").update(
|
|
patched_credential.model_dump(mode="json"), Query().id == hex_id
|
|
)
|
|
return hex_id
|
|
|
|
|
|
@validate_call
|
|
async def search(
|
|
name: constr(strip_whitespace=True, min_length=0), join_credentials: bool = True
|
|
):
|
|
db_params = evaluate_db_params()
|
|
|
|
def search_name(s):
|
|
return name in s
|
|
|
|
async with TinyDB(**db_params) as db:
|
|
matches = db.table("users").search(Query().login.test(search_name))
|
|
|
|
return [
|
|
await get(user["id"], join_credentials=join_credentials) for user in matches
|
|
]
|