Skip to content

Commit 88a38c9

Browse files
authored
feat: add Group Managers and Group Teams API support (#200)
1 parent e90cc8d commit 88a38c9

File tree

8 files changed

+389
-2
lines changed

8 files changed

+389
-2
lines changed

crowdin_api/api_resources/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
class PatchOperation(Enum):
5+
ADD = "add"
56
TEST = "test"
67
REPLACE = "replace"
78
REMOVE = "remove"

crowdin_api/api_resources/teams/resource.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from typing import Optional, Iterable
22

33
from crowdin_api.api_resources.abstract.resources import BaseResource
4-
from crowdin_api.api_resources.teams.types import Permissions, TeamPatchRequest, TeamByProjectRole
4+
from crowdin_api.api_resources.teams.types \
5+
import Permissions, TeamPatchRequest, TeamByProjectRole, GroupTeamPatchRequest
56
from crowdin_api.sorting import Sorting
67

78

@@ -29,6 +30,69 @@ def get_members_path(self, teamId: int, memberId: Optional[int] = None):
2930

3031
return f"teams/{teamId}/members"
3132

33+
def get_group_teams_path(self, group_id: int, team_id: Optional[int] = None):
34+
if team_id is not None:
35+
return f"groups/{group_id}/teams/{team_id}"
36+
37+
return f"groups/{group_id}/teams"
38+
39+
def list_group_teams(
40+
self,
41+
group_id: int,
42+
order_by: Optional[Sorting] = None
43+
):
44+
"""
45+
List Group Teams
46+
47+
Link to documentation for enterprise:
48+
https://support.crowdin.com/developer/enterprise/api/v2/#tag/Teams/operation/api.groups.teams.getMany
49+
"""
50+
51+
params = {
52+
"orderBy": order_by
53+
}
54+
55+
return self.requester.request(
56+
method="get",
57+
path=self.get_group_teams_path(group_id),
58+
params=params
59+
)
60+
61+
def update_group_teams(
62+
self,
63+
group_id: int,
64+
request_data: Iterable[GroupTeamPatchRequest]
65+
):
66+
"""
67+
Update Group Teams
68+
69+
Link to documentation for enterprise:
70+
https://support.crowdin.com/developer/enterprise/api/v2/#tag/Teams/operation/api.groups.teams.patch
71+
"""
72+
73+
return self.requester.request(
74+
method="patch",
75+
path=self.get_group_teams_path(group_id),
76+
request_data=request_data
77+
)
78+
79+
def get_group_team(
80+
self,
81+
group_id: int,
82+
team_id: int
83+
):
84+
"""
85+
Get Group Team
86+
87+
Link to documentation for enterprise:
88+
https://support.crowdin.com/developer/enterprise/api/v2/#tag/Teams/operation/api.groups.teams.get
89+
"""
90+
91+
return self.requester.request(
92+
method="get",
93+
path=self.get_group_teams_path(group_id, team_id)
94+
)
95+
3296
def add_team_to_project(
3397
self,
3498
teamId: int,

crowdin_api/api_resources/teams/tests/test_teams_resources.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from crowdin_api.api_resources import TeamsResource
66
from crowdin_api.api_resources.enums import PatchOperation
77
from crowdin_api.api_resources.teams.enums import ListTeamsOrderBy, TeamPatchPath
8+
from crowdin_api.api_resources.users.enums import ListGroupTeamsOrderBy
89
from crowdin_api.requester import APIRequester
910
from crowdin_api.sorting import Sorting, SortingOrder, SortingRule
1011

@@ -46,6 +47,118 @@ def test_get_members_path(self, incoming_data, path, base_absolut_url):
4647
resource = self.get_resource(base_absolut_url)
4748
assert resource.get_members_path(**incoming_data) == path
4849

50+
@pytest.mark.parametrize(
51+
"group_id, team_id, path",
52+
(
53+
(1, None, "groups/1/teams"),
54+
(1, 2000, "groups/1/teams/2000")
55+
)
56+
)
57+
def test_get_group_teams_path(self, group_id, team_id, path, base_absolut_url):
58+
resource = self.get_resource(base_absolut_url)
59+
assert resource.get_group_teams_path(group_id, team_id) == path
60+
61+
@pytest.mark.parametrize(
62+
"in_params, request_params",
63+
(
64+
(
65+
{},
66+
{
67+
"orderBy": None
68+
}
69+
),
70+
(
71+
{
72+
"order_by": Sorting(
73+
[
74+
SortingRule(
75+
ListGroupTeamsOrderBy.ID,
76+
SortingOrder.DESC,
77+
)
78+
]
79+
),
80+
},
81+
{
82+
"orderBy": Sorting(
83+
[
84+
SortingRule(
85+
ListGroupTeamsOrderBy.ID,
86+
SortingOrder.DESC,
87+
)
88+
]
89+
),
90+
}
91+
)
92+
)
93+
)
94+
@mock.patch("crowdin_api.requester.APIRequester.request")
95+
def test_list_group_teams(self, m_request, in_params, request_params, base_absolut_url):
96+
m_request.return_value = "response"
97+
98+
resource = self.get_resource(base_absolut_url)
99+
assert resource.list_group_teams(group_id=1, **in_params) == "response"
100+
m_request.assert_called_once_with(
101+
method="get",
102+
path="groups/1/teams",
103+
params=request_params
104+
)
105+
106+
@pytest.mark.parametrize(
107+
"in_params, request_params",
108+
(
109+
(
110+
[
111+
{
112+
"op": "add",
113+
"path": "/-",
114+
"value": {
115+
"teamId": 18
116+
}
117+
},
118+
{
119+
"op": "remove",
120+
"path": "/24"
121+
}
122+
],
123+
[
124+
{
125+
"op": "add",
126+
"path": "/-",
127+
"value": {
128+
"teamId": 18
129+
}
130+
},
131+
{
132+
"op": "remove",
133+
"path": "/24"
134+
}
135+
],
136+
),
137+
)
138+
)
139+
@mock.patch("crowdin_api.requester.APIRequester.request")
140+
def test_update_group_teams(self, m_request, in_params, request_params, base_absolut_url):
141+
m_request.return_value = "response"
142+
143+
resource = self.get_resource(base_absolut_url)
144+
assert resource.update_group_teams(group_id=1, request_data=in_params) == "response"
145+
m_request.assert_called_once_with(
146+
method="patch",
147+
path="groups/1/teams",
148+
request_data=request_params
149+
)
150+
151+
@mock.patch("crowdin_api.requester.APIRequester.request")
152+
def test_get_group_team(self, m_request, base_absolut_url):
153+
m_request.return_value = "response"
154+
155+
resource = self.get_resource(base_absolut_url)
156+
assert resource.get_group_team(group_id=1, team_id=2) == "response"
157+
m_request.assert_called_once_with(
158+
method="get",
159+
path="groups/1/teams/2"
160+
)
161+
49162
@pytest.mark.parametrize(
50163
"incoming_data, request_data",
51164
(

crowdin_api/api_resources/teams/types.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,9 @@ class RolePermission(TypedDict):
3838
class TeamByProjectRole(TypedDict):
3939
name: TeamRole
4040
permissions: RolePermission
41+
42+
43+
class GroupTeamPatchRequest(TypedDict):
44+
op: PatchOperation
45+
path: str
46+
value: Any

crowdin_api/api_resources/users/enums.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,19 @@ class ListProjectMembersEnterpriseOrderBy(Enum):
3232
USERNAME = "username"
3333
FIRST_NAME = "firstName"
3434
LAST_NAME = "lastName"
35+
36+
37+
class ListGroupManagersOrderBy(Enum):
38+
ID = "id"
39+
USERNAME = "username"
40+
EMAIL = "email"
41+
STATUS = "status"
42+
CREATED_AT = "createdAt"
43+
LAST_SEEN = "lastSeen"
44+
45+
46+
class ListGroupTeamsOrderBy(Enum):
47+
ID = "id"
48+
NAME = "name"
49+
CREATED_AT = "createdAt"
50+
UPDATED_AT = "updatedAt"

crowdin_api/api_resources/users/resource.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from crowdin_api.api_resources.abstract.resources import BaseResource
44
from crowdin_api.api_resources.users.enums import UserRole
5-
from crowdin_api.api_resources.users.types import UserPatchRequest, ProjectMemberRole
5+
from crowdin_api.api_resources.users.types import UserPatchRequest, ProjectMemberRole, GroupManagerPatchRequest
66
from crowdin_api.sorting import Sorting
77

88

@@ -120,6 +120,71 @@ def get_users_path(self, userId: Optional[int] = None):
120120

121121
return "users"
122122

123+
def get_group_managers_path(self, group_id: int, user_id: Optional[int] = None):
124+
if user_id is not None:
125+
return f"groups/{group_id}/managers/{user_id}"
126+
127+
return f"groups/{group_id}/managers"
128+
129+
def list_group_managers(
130+
self,
131+
group_id: int,
132+
team_ids: Optional[Iterable[int]] = None,
133+
order_by: Optional[Sorting] = None
134+
):
135+
"""
136+
List Group Managers
137+
138+
Link to documentation for enterprise:
139+
https://support.crowdin.com/developer/enterprise/api/v2/#tag/Users/operation/api.groups.managers.getMany
140+
"""
141+
142+
params = {
143+
"team_ids": ",".join(str(teamId) for teamId in team_ids) if team_ids is not None else None,
144+
"order_by": order_by
145+
}
146+
147+
return self.requester.request(
148+
method="get",
149+
path=self.get_group_managers_path(group_id),
150+
params=params
151+
)
152+
153+
def update_group_managers(
154+
self,
155+
group_id: int,
156+
request_data: Iterable[GroupManagerPatchRequest]
157+
):
158+
"""
159+
Update Group Managers
160+
161+
Link to documentation for enterprise:
162+
https://support.crowdin.com/developer/enterprise/api/v2/#tag/Users/operation/api.groups.managers.patch
163+
"""
164+
165+
return self.requester.request(
166+
method="patch",
167+
path=self.get_group_managers_path(group_id),
168+
request_data=request_data
169+
)
170+
171+
def get_group_manager(
172+
self,
173+
group_id: int,
174+
user_id: int
175+
):
176+
"""
177+
Get Group Manager
178+
179+
Link to documentation for enterprise:
180+
https://support.crowdin.com/developer/enterprise/api/v2/#tag/Users/operation/api.groups.managers.get
181+
"""
182+
183+
return self.requester.request(
184+
method="get",
185+
path=self.get_group_managers_path(group_id, user_id)
186+
)
187+
123188
def list_project_members(
124189
self,
125190
projectId: Optional[int] = None,

0 commit comments

Comments
 (0)