mailu: preserve keycloak profile fields

This commit is contained in:
Brad Stein 2026-01-18 01:08:31 -03:00
parent 418d201da0
commit 9c2cb1b037
2 changed files with 31 additions and 19 deletions

View File

@ -55,11 +55,11 @@ class _FakeResponse:
class _FakeSession:
def __init__(self, put_resp, get_resp):
def __init__(self, put_resp, get_resps):
self.put_resp = put_resp
self.get_resp = get_resp
self.get_resps = list(get_resps)
self.put_called = False
self.get_called = False
self.get_calls = 0
def post(self, *args, **kwargs):
return _FakeResponse({"access_token": "dummy"})
@ -69,22 +69,26 @@ class _FakeSession:
return self.put_resp
def get(self, *args, **kwargs):
self.get_called = True
return self.get_resp
self.get_calls += 1
if self.get_resps:
return self.get_resps.pop(0)
return _FakeResponse({})
def test_kc_update_attributes_succeeds(monkeypatch):
sync = load_sync_module(monkeypatch)
current_resp = _FakeResponse({"attributes": {}})
ok_resp = _FakeResponse({"attributes": {"mailu_app_password": ["abc"]}})
sync.SESSION = _FakeSession(_FakeResponse({}), ok_resp)
sync.SESSION = _FakeSession(_FakeResponse({}), [current_resp, ok_resp])
sync.kc_update_attributes("token", {"id": "u1", "username": "u1"}, {"mailu_app_password": "abc"})
assert sync.SESSION.put_called and sync.SESSION.get_called
assert sync.SESSION.put_called and sync.SESSION.get_calls == 2
def test_kc_update_attributes_raises_without_attribute(monkeypatch):
sync = load_sync_module(monkeypatch)
current_resp = _FakeResponse({"attributes": {}})
missing_attr_resp = _FakeResponse({"attributes": {}}, status=200)
sync.SESSION = _FakeSession(_FakeResponse({}), missing_attr_resp)
sync.SESSION = _FakeSession(_FakeResponse({}), [current_resp, missing_attr_resp])
with pytest.raises(Exception):
sync.kc_update_attributes("token", {"id": "u1", "username": "u1"}, {"mailu_app_password": "abc"})

View File

@ -87,7 +87,12 @@ def kc_get_users(token):
while True:
resp = SESSION.get(
f"{KC_BASE}/admin/realms/{KC_REALM}/users",
params={"first": first, "max": max_results, "enabled": "true"},
params={
"first": first,
"max": max_results,
"enabled": "true",
"briefRepresentation": "false",
},
headers=headers,
timeout=20,
)
@ -105,17 +110,20 @@ def kc_update_attributes(token, user, attributes):
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
payload = {
"firstName": user.get("firstName"),
"lastName": user.get("lastName"),
"email": user.get("email"),
"enabled": user.get("enabled", True),
"username": user["username"],
"emailVerified": user.get("emailVerified", False),
"attributes": attributes,
}
user_url = f"{KC_BASE}/admin/realms/{KC_REALM}/users/{user['id']}"
resp = SESSION.put(user_url, headers=headers, json=payload, timeout=20)
current = SESSION.get(
user_url,
headers={"Authorization": f"Bearer {token}"},
params={"briefRepresentation": "false"},
timeout=15,
)
current.raise_for_status()
current_payload = current.json()
current_attrs = current_payload.get("attributes") if isinstance(current_payload, dict) else None
if not isinstance(current_attrs, dict):
current_attrs = {}
current_attrs.update(attributes)
resp = SESSION.put(user_url, headers=headers, json={"attributes": current_attrs}, timeout=20)
resp.raise_for_status()
verify = SESSION.get(
user_url,