From da6bd22199a50cfb8dd1066aee0f0463420a62ca Mon Sep 17 00:00:00 2001 From: luxferre Date: Fri, 12 Jun 2026 16:44:45 +0100 Subject: [PATCH 1/3] minor: typo --- src/iam/router.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iam/router.py b/src/iam/router.py index 5096bde..10dc52e 100644 --- a/src/iam/router.py +++ b/src/iam/router.py @@ -612,7 +612,7 @@ async def invitation( @router.put( - path="/group/user//invitation/accept", + path="/group/user/invitation/accept", summary="Accept email invitation to join an org's group", status_code=status.HTTP_200_OK, response_model=IAMPutGroupInvitationAcceptResponse, From 2b4c875da3673648bc5d3211474a80daf51d2ae2 Mon Sep 17 00:00:00 2001 From: luxferre Date: Mon, 15 Jun 2026 09:31:36 +0100 Subject: [PATCH 2/3] tests: group invitation --- test/test_iam.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/test/test_iam.py b/test/test_iam.py index 3315fb0..3980eea 100644 --- a/test/test_iam.py +++ b/test/test_iam.py @@ -675,3 +675,77 @@ async def test_delete_group_users_success(default_client: AsyncClient): assert "group" in data assert data["group"]["id"] == 1 assert data["group"]["name"] == "Org One Group" + + +@pytest.mark.anyio +async def test_put_group_user_invitation_success(default_client: AsyncClient): + body = {"user_email": "admin@test.com", "organisation_id": 1, "group_id": 1} + resp = await default_client.put("/iam/group/user/invitation", json=body) + + assert resp.status_code == 200 + data = resp.json() + assert "organisation" in data + assert isinstance(data["organisation"], dict) + assert data["organisation"]["id"] == 1 + assert data["organisation"]["name"] == "Org One" + + assert "invited_email" in data + assert isinstance(data["invited_email"], str) + assert data["invited_email"] == "admin@test.com" + + assert "group" in data + assert isinstance(data["group"], dict) + assert data["group"]["name"] == "Org One Group" + assert data["group"]["id"] == 1 + + +@pytest.mark.parametrize( + "body, expected_status", + [ + ({"organisation_id": 42, "user_email": "admin@test.com", "group_id": 1}, 404), + ( + { + "organisation_id": "Test Org", + "user_email": "admin@test.com", + "group_id": 1, + }, + 422, + ), + ({"organisation_id": "", "user_email": "admin@test.com", "group_id": 1}, 422), + ({}, 422), + ({"user_email": 42, "group_id": 1}, 422), + ({"organisation_id": 1, "user_email": "Test User", "group_id": 1}, 422), + ({"organisation_id": 1, "user_email": "admin@test.com", "group_id": 42}, 404), + ({"organisation_id": "Test Org", "user_email": "admin@test.com"}, 422), + ({"organisation_id": "", "user_email": "admin@test.com"}, 422), + ({"user_email": 42}, 422), + ], +) +@pytest.mark.anyio +async def test_put_group_user_invitation_status_checks( + default_client: AsyncClient, body, expected_status +): + resp = await default_client.put("/iam/group/user/invitation", json=body) + + assert resp.status_code == expected_status + + +@pytest.mark.parametrize( + "body, expected_status", + [ + ({"jwt": "invalid"}, 401), + ({"jwt": ""}, 401), + ({"jwt": None}, 422), + ({"jwt": 42}, 422), + ], +) +@pytest.mark.anyio +async def test_put_group_user_invitation_accept_status_checks( + default_client: AsyncClient, body, expected_status +): + resp = await default_client.put("/iam/group/user/invitation/accept", json=body) + + assert resp.status_code == expected_status + + if resp.status_code == 401: + assert resp.json()["detail"] == "Invalid JWS" From 3f7abc5986b791e9c5d213f0fbae7ad8fb09a633 Mon Sep 17 00:00:00 2001 From: luxferre Date: Mon, 15 Jun 2026 09:33:51 +0100 Subject: [PATCH 3/3] tests: preapproval Issue: #24 --- test/test_auth_approval.py | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/test_auth_approval.py b/test/test_auth_approval.py index 3f4dd03..f038e51 100644 --- a/test/test_auth_approval.py +++ b/test/test_auth_approval.py @@ -136,3 +136,55 @@ async def test_post_iam_permissions_search_auth_approval(no_su_client: AsyncClie ) assert resp.status_code != 422 assert "has not been approved." in resp.json()["detail"] + + +@pytest.mark.anyio +async def test_delete_org_user_auth_approval(no_su_client: AsyncClient): + resp = await no_su_client.delete("/org/user?org_id=3&user_id=1") + + assert resp.status_code != 422 + assert "has not been approved." in resp.json()["detail"] + + +@pytest.mark.anyio +async def test_delete_preapproval_auth_approval(no_su_client: AsyncClient): + resp = await no_su_client.delete("/org/self?org_id=3") + + assert resp.status_code != 422 + assert resp.status_code == 204 + + +@pytest.mark.anyio +async def test_post_user_invitation_auth_approval(no_su_client: AsyncClient): + body = {"user_email": "admin@test.com", "organisation_id": 3} + resp = await no_su_client.post("/user/invitation", json=body) + + assert resp.status_code != 422 + assert "has not been approved." in resp.json()["detail"] + + +@pytest.mark.anyio +async def test_delete_group_permissions_auth_approval(no_su_client: AsyncClient): + resp = await no_su_client.delete( + "/iam/group/permission?org_id=3&group_id=1&perm_id=1" + ) + + assert resp.status_code != 422 + assert "has not been approved." in resp.json()["detail"] + + +@pytest.mark.anyio +async def test_delete_group_users_success(no_su_client: AsyncClient): + resp = await no_su_client.delete("/iam/group/user?org_id=3&group_id=1&user_id=1") + + assert resp.status_code != 422 + assert "has not been approved." in resp.json()["detail"] + + +@pytest.mark.anyio +async def test_put_group_user_invitation_success(no_su_client: AsyncClient): + body = {"user_email": "admin@test.com", "organisation_id": 3, "group_id": 1} + resp = await no_su_client.put("/iam/group/user/invitation", json=body) + + assert resp.status_code != 422 + assert "has not been approved." in resp.json()["detail"]