Skip to content

Commit 35e847e

Browse files
authored
fix: assistant share links cannot be unshared (#1411)
## Anonymous Sessions ### Resolved Issues - Fixed: Removing an anonymous session link may fail because of lazy loading updates.
1 parent 8e576b4 commit 35e847e

3 files changed

Lines changed: 81 additions & 1 deletion

File tree

pingpong/models.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,6 +2690,17 @@ async def get_by_id(cls, session: AsyncSession, id_: int) -> "AnonymousLink":
26902690
stmt = select(AnonymousLink).where(AnonymousLink.id == int(id_))
26912691
return await session.scalar(stmt)
26922692

2693+
@classmethod
2694+
async def get_by_id_with_assistant(
2695+
cls, session: AsyncSession, id_: int
2696+
) -> "AnonymousLink":
2697+
stmt = (
2698+
select(AnonymousLink)
2699+
.where(AnonymousLink.id == int(id_))
2700+
.options(selectinload(AnonymousLink.assistant))
2701+
)
2702+
return await session.scalar(stmt)
2703+
26932704
@classmethod
26942705
async def revoke(cls, session: AsyncSession, id_: int) -> "AnonymousLink":
26952706
stmt = (

pingpong/server.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7702,7 +7702,9 @@ async def unshare_assistant(
77027702
"""
77037703
asst, share_link = await asyncio.gather(
77047704
models.Assistant.get_by_id(request.state["db"], int(assistant_id)),
7705-
models.AnonymousLink.get_by_id(request.state["db"], int(share_id)),
7705+
models.AnonymousLink.get_by_id_with_assistant(
7706+
request.state["db"], int(share_id)
7707+
),
77067708
)
77077709
if not asst:
77087710
raise HTTPException(

pingpong/test_assistant_sharing.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from pingpong import models
2+
import pingpong.schemas as schemas
3+
4+
from .testutil import with_authz, with_institution, with_user
5+
6+
7+
@with_user(123)
8+
@with_institution(1, "Test Institution")
9+
@with_authz(
10+
grants=[
11+
("user:123", "can_edit", "assistant:1"),
12+
("user:123", "can_share_assistants", "class:1"),
13+
]
14+
)
15+
async def test_unshare_assistant_revokes_share_without_lazy_loading(
16+
api, db, institution, valid_user_token
17+
):
18+
async with db.async_session() as session:
19+
creator = models.User(email="creator@test.org")
20+
session.add(creator)
21+
await session.flush()
22+
23+
class_ = models.Class(
24+
id=1,
25+
name="Test Class",
26+
institution_id=institution.id,
27+
)
28+
session.add(class_)
29+
await session.flush()
30+
31+
assistant = models.Assistant(
32+
id=1,
33+
name="Test Assistant",
34+
instructions="Test instructions",
35+
description="Test description",
36+
interaction_mode=schemas.InteractionMode.CHAT,
37+
model="gpt-4o-mini",
38+
temperature=0.2,
39+
class_id=class_.id,
40+
tools="[]",
41+
creator_id=creator.id,
42+
published=None,
43+
version=3,
44+
)
45+
session.add(assistant)
46+
await session.flush()
47+
48+
share_link = await models.AnonymousLink.create(
49+
session,
50+
share_token="share-token-123",
51+
assistant_id=assistant.id,
52+
)
53+
await session.commit()
54+
55+
response = api.delete(
56+
f"/api/v1/class/{class_.id}/assistant/{assistant.id}/share/{share_link.id}",
57+
headers={"Authorization": f"Bearer {valid_user_token}"},
58+
)
59+
assert response.status_code == 200
60+
assert response.json() == {"status": "ok"}
61+
62+
async with db.async_session() as session:
63+
updated_share_link = await models.AnonymousLink.get_by_id(
64+
session, share_link.id
65+
)
66+
assert updated_share_link.active is False
67+
assert updated_share_link.revoked_at is not None

0 commit comments

Comments
 (0)