svc-infra 0.1.184__py3-none-any.whl → 0.1.185__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.
- svc_infra/auth/user_default.py +63 -35
- {svc_infra-0.1.184.dist-info → svc_infra-0.1.185.dist-info}/METADATA +1 -1
- {svc_infra-0.1.184.dist-info → svc_infra-0.1.185.dist-info}/RECORD +5 -5
- {svc_infra-0.1.184.dist-info → svc_infra-0.1.185.dist-info}/WHEEL +0 -0
- {svc_infra-0.1.184.dist-info → svc_infra-0.1.185.dist-info}/entry_points.txt +0 -0
svc_infra/auth/user_default.py
CHANGED
@@ -8,46 +8,74 @@ from svc_infra.api.fastapi.db.repository import Repository
|
|
8
8
|
|
9
9
|
_pwd = PasswordHelper()
|
10
10
|
|
11
|
-
def _user_pre_create(data: Dict[str, Any]) -> Dict[str, Any]:
|
12
|
-
data = dict(data)
|
13
|
-
# normalize + map fields
|
14
|
-
if "password" in data:
|
15
|
-
data["password_hash"] = _pwd.hash(data.pop("password"))
|
16
|
-
if "metadata" in data:
|
17
|
-
data["extra"] = data.pop("metadata")
|
18
|
-
|
19
|
-
# BEFORE insert: application-level guard (nice error)
|
20
|
-
# case-insensitive email; handle tenant/null logic the same way as your unique index
|
21
|
-
email = data.get("email")
|
22
|
-
tenant_id = data.get("tenant_id")
|
23
|
-
if email:
|
24
|
-
where = [func.lower(Repository.model.email) == func.lower(email)]
|
25
|
-
if tenant_id is None:
|
26
|
-
where.append(Repository.model.tenant_id.is_(None))
|
27
|
-
else:
|
28
|
-
where.append(Repository.model.tenant_id == tenant_id)
|
29
|
-
|
30
|
-
# use a small “exists” helper on the repo if you have it
|
31
|
-
async def _exists(session):
|
32
|
-
return await Repository.exists(session, where=where)
|
33
|
-
|
34
|
-
data["_precreate_exists_check"] = _exists # stash callable for service.create to run
|
35
|
-
|
36
|
-
return data
|
37
|
-
|
38
|
-
def _user_pre_update(data: Dict[str, Any]) -> Dict[str, Any]:
|
39
|
-
data = dict(data)
|
40
|
-
if "password" in data:
|
41
|
-
data["password_hash"] = _pwd.hash(data.pop("password"))
|
42
|
-
if "metadata" in data:
|
43
|
-
data["extra"] = data.pop("metadata")
|
44
|
-
return data
|
45
|
-
|
46
11
|
def make_default_user_service(repo: Repository):
|
12
|
+
Model = repo.model # <-- capture the actual mapped model from the repo
|
13
|
+
|
14
|
+
def _user_pre_create(data: Dict[str, Any]) -> Dict[str, Any]:
|
15
|
+
data = dict(data)
|
16
|
+
# normalize + map fields
|
17
|
+
if "password" in data:
|
18
|
+
data["password_hash"] = _pwd.hash(data.pop("password"))
|
19
|
+
if "metadata" in data:
|
20
|
+
data["extra"] = data.pop("metadata")
|
21
|
+
data.setdefault("roles", [])
|
22
|
+
|
23
|
+
# BEFORE insert: app-level guard (nice 409) aligned with DB uniqueness
|
24
|
+
email = data.get("email")
|
25
|
+
tenant_id = data.get("tenant_id")
|
26
|
+
if email is not None:
|
27
|
+
# case-insensitive email; scope by tenant (NULL => global)
|
28
|
+
where = [func.lower(Model.email) == func.lower(email)]
|
29
|
+
if hasattr(Model, "tenant_id"):
|
30
|
+
if tenant_id is None:
|
31
|
+
where.append(Model.tenant_id.is_(None))
|
32
|
+
else:
|
33
|
+
where.append(Model.tenant_id == tenant_id)
|
34
|
+
|
35
|
+
async def _exists(session):
|
36
|
+
return await repo.exists(session, where=where)
|
37
|
+
|
38
|
+
# stash the callback so Service.create can await it (has session)
|
39
|
+
data["_precreate_exists_check"] = _exists
|
40
|
+
|
41
|
+
return data
|
42
|
+
|
43
|
+
def _user_pre_update(data: Dict[str, Any]) -> Dict[str, Any]:
|
44
|
+
data = dict(data)
|
45
|
+
if "password" in data:
|
46
|
+
data["password_hash"] = _pwd.hash(data.pop("password"))
|
47
|
+
if "metadata" in data:
|
48
|
+
data["extra"] = data.pop("metadata")
|
49
|
+
|
50
|
+
# Optional: also protect email change from creating dupes
|
51
|
+
email = data.get("email")
|
52
|
+
tenant_id = data.get("tenant_id")
|
53
|
+
if email is not None:
|
54
|
+
where = [func.lower(Model.email) == func.lower(email)]
|
55
|
+
if hasattr(Model, "tenant_id"):
|
56
|
+
if tenant_id is None:
|
57
|
+
where.append(Model.tenant_id.is_(None))
|
58
|
+
else:
|
59
|
+
where.append(Model.tenant_id == tenant_id)
|
60
|
+
|
61
|
+
async def _exists(session):
|
62
|
+
return await repo.exists(session, where=where)
|
63
|
+
|
64
|
+
data["_precreate_exists_check"] = _exists # reuse same key
|
65
|
+
|
66
|
+
return data
|
67
|
+
|
47
68
|
class _Svc(ServiceWithHooks):
|
48
69
|
async def create(self, session, data):
|
49
70
|
exists_cb = data.pop("_precreate_exists_check", None)
|
50
71
|
if exists_cb and await exists_cb(session):
|
51
72
|
raise HTTPException(status_code=409, detail="User with this email already exists.")
|
52
73
|
return await super().create(session, data)
|
74
|
+
|
75
|
+
async def update(self, session, id_value, data):
|
76
|
+
exists_cb = data.pop("_precreate_exists_check", None)
|
77
|
+
if exists_cb and await exists_cb(session):
|
78
|
+
raise HTTPException(status_code=409, detail="User with this email already exists.")
|
79
|
+
return await super().update(session, id_value, data)
|
80
|
+
|
53
81
|
return _Svc(repo, pre_create=_user_pre_create, pre_update=_user_pre_update)
|
@@ -32,7 +32,7 @@ svc_infra/auth/integration.py,sha256=L230xUw7vRM0AJIZwNzufRQrfNTPRdczp4BPd_NILeo
|
|
32
32
|
svc_infra/auth/oauth_router.py,sha256=JY3VQ9_0oS_a2gGg418IDG2TbK79sQWcpA9KPiOAfjY,4918
|
33
33
|
svc_infra/auth/providers.py,sha256=fiw0ouuGKtwcwMY0Zw7cEv-CXNaUYDnqo_NmiWiB8Lc,3185
|
34
34
|
svc_infra/auth/settings.py,sha256=wVCLQnpA9M6zfiWyUpSdn9fo4q-Z4WpVyC3KvkG3HYg,1742
|
35
|
-
svc_infra/auth/user_default.py,sha256=
|
35
|
+
svc_infra/auth/user_default.py,sha256=D6oMni4YyFeb1muws0CokC20t-R0FwMH28HMmSEJnMw,3290
|
36
36
|
svc_infra/auth/users.py,sha256=4rlTCELU-po7bF7u6z02Bd8pXLGcLI2Adj0VjA-gg5E,2098
|
37
37
|
svc_infra/cli/__init__.py,sha256=g47RSROuFW8LSsB6WFNSus5BnUl9z_DrPK9idYo3O6M,401
|
38
38
|
svc_infra/cli/cmds/__init__.py,sha256=263YKSg73Ik-SQeilyGePdc663BYi4RfBrc0wMFxeoU,212
|
@@ -77,7 +77,7 @@ svc_infra/observability/templates/prometheus_rules.yml,sha256=sbVLm1h40FMkGSeWO4
|
|
77
77
|
svc_infra/observability/tracing/__init__.py,sha256=TOs2yCicqBdo4OfOHTMmqeHsn7DBRu5EdvF2L5f31Y0,237
|
78
78
|
svc_infra/observability/tracing/setup.py,sha256=21Ob276U4KZOs6M2o1O79wQXFHV0gY6YdMyjeqMrzMU,5042
|
79
79
|
svc_infra/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
80
|
-
svc_infra-0.1.
|
81
|
-
svc_infra-0.1.
|
82
|
-
svc_infra-0.1.
|
83
|
-
svc_infra-0.1.
|
80
|
+
svc_infra-0.1.185.dist-info/METADATA,sha256=PubOT8LUdQnRSSJXHLtHa4V1EgFEGLyDSIyAFVwe_pw,4981
|
81
|
+
svc_infra-0.1.185.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
82
|
+
svc_infra-0.1.185.dist-info/entry_points.txt,sha256=6x_nZOsjvn6hRZsMgZLgTasaCSKCgAjsGhACe_CiP0U,48
|
83
|
+
svc_infra-0.1.185.dist-info/RECORD,,
|
File without changes
|
File without changes
|