Skip to content

Commit f7e1a9f

Browse files
Lingling PengLingling Peng
authored andcommitted
add teamMembershipStatus dataclass
1 parent d636253 commit f7e1a9f

File tree

5 files changed

+124
-19
lines changed

5 files changed

+124
-19
lines changed

synapseclient/models/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
TableUpdateTransaction,
3535
UploadToTableRequest,
3636
)
37-
from synapseclient.models.team import Team, TeamMember
37+
from synapseclient.models.team import Team, TeamMember, TeamMembershipStatus
3838
from synapseclient.models.user import UserGroupHeader, UserPreference, UserProfile
3939
from synapseclient.models.virtualtable import VirtualTable
4040

@@ -50,6 +50,7 @@
5050
"Annotations",
5151
"Team",
5252
"TeamMember",
53+
"TeamMembershipStatus",
5354
"UserProfile",
5455
"UserPreference",
5556
"UserGroupHeader",

synapseclient/models/protocols/team_protocol.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from synapseclient import Synapse
77

88
if TYPE_CHECKING:
9-
from synapseclient.models import Team, TeamMember
9+
from synapseclient.models import Team, TeamMember, TeamMembershipStatus
1010

1111

1212
class TeamSynchronousProtocol(Protocol):
@@ -166,7 +166,7 @@ def get_user_membership_status(
166166
team: Union[int, str],
167167
*,
168168
synapse_client: Optional[Synapse] = None,
169-
) -> Dict[str, str]:
169+
) -> "TeamMembershipStatus":
170170
"""Retrieve a user's Team Membership Status bundle.
171171
172172
<https://rest-docs.synapse.org/rest/GET/team/id/member/principalId/membershipStatus.html>
@@ -179,6 +179,8 @@ def get_user_membership_status(
179179
instance from the Synapse class constructor.
180180
181181
Returns:
182-
A dictionary of TeamMembershipStatus
182+
TeamMembershipStatus object
183183
"""
184-
return {}
184+
from synapseclient.models.team import TeamMembershipStatus
185+
186+
return TeamMembershipStatus().fill_from_dict({})

synapseclient/models/team.py

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,79 @@ def fill_from_dict(
5757
return self
5858

5959

60+
@dataclass
61+
class TeamMembershipStatus:
62+
"""
63+
Contains information about a user's membership status in a Team.
64+
In practice the constructor is not called directly by the client.
65+
66+
Attributes:
67+
team_id: The synapse ID of the team
68+
user_id: The synapse ID of the user
69+
is_member: Whether the user is a member of the team
70+
has_open_invitation: Whether the user has an open invitation to join the team
71+
has_open_request: Whether the user has an open request to join the team
72+
can_join: Whether the user can join the team
73+
membership_approval_required: Whether membership approval is required for the team
74+
has_unmet_access_requirement: Whether the user has unmet access requirements
75+
can_send_email: Whether the user can send email to the team
76+
"""
77+
78+
team_id: Optional[str] = None
79+
"""The ID of the team"""
80+
81+
user_id: Optional[str] = None
82+
"""The ID of the user"""
83+
84+
is_member: Optional[bool] = None
85+
"""Whether the user is a member of the team"""
86+
87+
has_open_invitation: Optional[bool] = None
88+
"""Whether the user has an open invitation to join the team"""
89+
90+
has_open_request: Optional[bool] = None
91+
"""Whether the user has an open request to join the team"""
92+
93+
can_join: Optional[bool] = None
94+
"""Whether the user can join the team"""
95+
96+
membership_approval_required: Optional[bool] = None
97+
"""Whether membership approval is required for the team"""
98+
99+
has_unmet_access_requirement: Optional[bool] = None
100+
"""Whether the user has unmet access requirements"""
101+
102+
can_send_email: Optional[bool] = None
103+
"""Whether the user can send email to the team"""
104+
105+
def fill_from_dict(
106+
self, membership_status_dict: Dict[str, Union[str, bool]]
107+
) -> "TeamMembershipStatus":
108+
"""
109+
Converts a response from the REST API into this dataclass.
110+
111+
Arguments:
112+
membership_status_dict: The response from the REST API.
113+
114+
Returns:
115+
The TeamMembershipStatus object.
116+
"""
117+
self.team_id = membership_status_dict.get("teamId", None)
118+
self.user_id = membership_status_dict.get("userId", None)
119+
self.is_member = membership_status_dict.get("isMember", None)
120+
self.has_open_invitation = membership_status_dict.get("hasOpenInvitation", None)
121+
self.has_open_request = membership_status_dict.get("hasOpenRequest", None)
122+
self.can_join = membership_status_dict.get("canJoin", None)
123+
self.membership_approval_required = membership_status_dict.get(
124+
"membershipApprovalRequired", None
125+
)
126+
self.has_unmet_access_requirement = membership_status_dict.get(
127+
"hasUnmetAccessRequirement", None
128+
)
129+
self.can_send_email = membership_status_dict.get("canSendEmail", None)
130+
return self
131+
132+
60133
@dataclass
61134
@async_to_sync
62135
class Team(TeamSynchronousProtocol):
@@ -364,7 +437,7 @@ async def get_user_membership_status_async(
364437
team: Union[str, int],
365438
*,
366439
synapse_client: Optional[Synapse] = None,
367-
) -> str:
440+
) -> TeamMembershipStatus:
368441
"""Retrieve a user's Team Membership Status bundle for this team.
369442
370443
Arguments:
@@ -375,12 +448,12 @@ async def get_user_membership_status_async(
375448
instance from the Synapse class constructor.
376449
377450
Returns:
378-
A dictionary of TeamMembershipStatus
451+
TeamMembershipStatus object
379452
"""
380453
from synapseclient import Synapse
381454

382455
client = Synapse.get_client(synapse_client=synapse_client)
383456
status = await get_membership_status(
384457
user_id=user_id, team=team, synapse_client=client
385458
)
386-
return status
459+
return TeamMembershipStatus().fill_from_dict(status)

tests/integration/synapseclient/models/async/test_team_async.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,8 @@ async def test_get_user_membership_status(self) -> None:
157157

158158
# THEN the creator should have membership status indicating they are a member
159159
assert creator_status is not None
160-
assert "teamId" in creator_status
161-
assert creator_status["teamId"] == str(test_team.id)
162-
assert "userId" in creator_status
163-
assert "isMember" in creator_status
164-
assert creator_status["isMember"] is True
160+
assert creator_status.team_id == str(test_team.id)
161+
assert creator_status.is_member is True
165162

166163
# WHEN I invite a test user to the team
167164
invite = await test_team.invite_async(
@@ -177,11 +174,11 @@ async def test_get_user_membership_status(self) -> None:
177174

178175
# THEN the invited user should show they have an open invitation
179176
assert invited_status is not None
180-
assert invited_status["teamId"] == str(test_team.id)
181-
assert invited_status["hasOpenInvitation"] is True
182-
assert invited_status["membershipApprovalRequired"] is True
183-
assert invited_status["canSendEmail"] is True
184-
assert invited_status["isMember"] is False
177+
assert invited_status.team_id == str(test_team.id)
178+
assert invited_status.has_open_invitation is True
179+
assert invited_status.membership_approval_required is True
180+
assert invited_status.can_send_email is True
181+
assert invited_status.is_member is False
185182

186183
finally:
187184
# Clean up

tests/unit/synapseclient/models/synchronous/unit_test_team.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import pytest
66

77
from synapseclient import Synapse
8-
from synapseclient.models.team import Team, TeamMember
8+
from synapseclient.models.team import Team, TeamMember, TeamMembershipStatus
99
from synapseclient.models.user import UserGroupHeader
1010

1111

@@ -25,6 +25,38 @@ def test_fill_from_dict(self) -> None:
2525
assert team_member.is_admin is True
2626

2727

28+
class TestTeamMembershipStatus:
29+
"""Tests for the TeamMembershipStatus class."""
30+
31+
def test_fill_from_dict(self) -> None:
32+
# GIVEN a blank TeamMembershipStatus
33+
status = TeamMembershipStatus()
34+
# WHEN I fill it with a dictionary
35+
status.fill_from_dict(
36+
{
37+
"teamId": "123",
38+
"userId": "456",
39+
"isMember": False,
40+
"hasOpenInvitation": True,
41+
"hasOpenRequest": False,
42+
"canJoin": False,
43+
"membershipApprovalRequired": True,
44+
"hasUnmetAccessRequirement": False,
45+
"canSendEmail": True,
46+
}
47+
)
48+
# THEN I expect all fields to be set
49+
assert status.team_id == "123"
50+
assert status.user_id == "456"
51+
assert status.is_member is False
52+
assert status.has_open_invitation is True
53+
assert status.has_open_request is False
54+
assert status.can_join is False
55+
assert status.membership_approval_required is True
56+
assert status.has_unmet_access_requirement is False
57+
assert status.can_send_email is True
58+
59+
2860
class TestTeam:
2961
"""Tests for the Team class."""
3062

0 commit comments

Comments
 (0)