Skip to content

Commit e572f32

Browse files
authored
Merge pull request #769 from CitrineInformatics/feature/PLA-9753-expose-cross-team-resource-listing-endpoints
Feature/pla 9753 expose cross team resource listing endpoints
2 parents 70382a9 + 1f44eea commit e572f32

File tree

4 files changed

+173
-1
lines changed

4 files changed

+173
-1
lines changed

docs/source/getting_started/teams.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,32 @@ A user's actions in a team can be updated. The method
125125
126126
# Make the user a member with read and write access
127127
team.update_user_actions(user_uid=user_id, actions=[READ, WRITE])
128+
129+
130+
Listing Publish Resources in a Team
131+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
132+
Teams can list the published IDs for datasets, modules, tables and table
133+
definitions available in a team. Using the `list_readable`,
134+
`list_writeable`, or `list_shareable` methods to list IDs with these
135+
permissions. Note: these calls return a list of string uids, not the
136+
complete resource objects.
137+
138+
:func:`~citrine.resources.team.Team.dataset_ids`,
139+
:func:`~citrine.resources.team.Team.module_ids`,
140+
:func:`~citrine.resources.team.Team.table_ids`,
141+
:func:`~citrine.resources.team.Team.table_definition_ids`.
142+
143+
144+
.. code-block:: python
145+
146+
team = citrine.teams.get("baaa467e-1758-43a8-97c7-76e569d0dcab")
147+
project1 = team.projects.get("8ad2f784-5c49-45ad-b525-6af859651acf")
148+
149+
dataset_ids = team.dataset_ids.list_readable()
150+
151+
# Use one of the IDs to get a handle to the resource from it's origin project:
152+
dataset = project1.datasets.get(dataset_ids[0])
153+
154+
# Pull this published resource into another project:
155+
project2 = team.projects.get("9ecb5610-6f69-4175-a1f8-bbfd7d711826")
156+
project2.pull_in_resource(resource=dataset)

src/citrine/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.35.1'
1+
__version__ = '1.36.0'

src/citrine/resources/team.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,79 @@ def __str__(self):
3333
.format(self.user.screen_name, self.actions, self.team.name)
3434

3535

36+
class TeamResourceIDs:
37+
"""
38+
A Citrine Team Resource IDs class.
39+
40+
This class is used to list the unique IDs for specific resource
41+
types published in a single team and therefore available to be pulled
42+
in by all projects.
43+
44+
Parameters
45+
----------
46+
team_id: str or uuid
47+
ID of the team.
48+
resource_type: str
49+
The resource type to list, one of DATASET/MODULE/TABLE/TABLE_DEFINITION
50+
51+
"""
52+
53+
_api_version = "v3"
54+
55+
def __init__(self,
56+
session: Session,
57+
team_id: Union[str, UUID],
58+
resource_type: str) -> None:
59+
self.session = session
60+
self.team_id = team_id
61+
self.resource_type = resource_type
62+
63+
def _path(self) -> str:
64+
return format_escaped_url(f'/teams/{self.team_id}')
65+
66+
def _list_ids(self, action: str) -> List[str]:
67+
query_params = {"domain": self._path(), "action": action}
68+
return self.session.get_resource(f"/{self.resource_type}/authorized-ids",
69+
params=query_params,
70+
version=self._api_version)['ids']
71+
72+
def list_readable(self):
73+
"""
74+
List IDs of the published resources with READ access.
75+
76+
Returns
77+
-------
78+
List[str]
79+
Returns a list of string UUIDs for each resource
80+
81+
"""
82+
return self._list_ids(action=READ)
83+
84+
def list_writeable(self):
85+
"""
86+
List IDs of the published resources with WRITE access.
87+
88+
Returns
89+
-------
90+
List[str]
91+
Returns a list of string UUIDs for each resource
92+
93+
"""
94+
return self._list_ids(action=WRITE)
95+
96+
def list_shareable(self):
97+
"""
98+
List IDs of the published resources with SHARE access.
99+
100+
Returns
101+
-------
102+
List[str]
103+
Returns a list of string UUIDs for each resource
104+
105+
"""
106+
return self._list_ids(action=SHARE)
107+
108+
36109
class Team(Resource['Team']):
37110
"""
38111
A Citrine Team.
@@ -292,6 +365,34 @@ def projects(self) -> ProjectCollection:
292365
"""Return a resource representing all visible projects in this team."""
293366
return ProjectCollection(self.session, team_id=self.uid)
294367

368+
@property
369+
def dataset_ids(self) -> TeamResourceIDs:
370+
"""Return a TeamResourceIDs instance for listing published dataset IDs."""
371+
return TeamResourceIDs(session=self.session,
372+
team_id=self.uid,
373+
resource_type=ResourceTypeEnum.DATASET.value)
374+
375+
@property
376+
def module_ids(self) -> TeamResourceIDs:
377+
"""Return a TeamResourceIDs instance for listing published module IDs."""
378+
return TeamResourceIDs(session=self.session,
379+
team_id=self.uid,
380+
resource_type=ResourceTypeEnum.MODULE.value)
381+
382+
@property
383+
def table_ids(self) -> TeamResourceIDs:
384+
"""Return a TeamResourceIDs instance for listing published table IDs."""
385+
return TeamResourceIDs(session=self.session,
386+
team_id=self.uid,
387+
resource_type=ResourceTypeEnum.TABLE.value)
388+
389+
@property
390+
def table_definition_ids(self) -> TeamResourceIDs:
391+
"""Return a TeamResourceIDs instance for listing published table definition IDs."""
392+
return TeamResourceIDs(session=self.session,
393+
team_id=self.uid,
394+
resource_type=ResourceTypeEnum.TABLE_DEFINITION.value)
395+
295396

296397
class TeamCollection(Collection[Team]):
297398
"""

tests/resources/test_team.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,45 @@ def test_un_share(team, other_team, session):
303303
)
304304
assert expect_call == session.last_call
305305
assert share_response is True
306+
307+
308+
@pytest.mark.parametrize("resource_type,method",
309+
[
310+
(ResourceTypeEnum.DATASET, "dataset_ids"),
311+
(ResourceTypeEnum.MODULE, "module_ids"),
312+
(ResourceTypeEnum.TABLE, "table_ids"),
313+
(ResourceTypeEnum.TABLE_DEFINITION, "table_definition_ids")
314+
])
315+
def test_list_resource_ids(team, session, resource_type, method):
316+
# Given
317+
read_response = {'ids': [uuid.uuid4(), uuid.uuid4()]}
318+
write_response = {'ids': [uuid.uuid4(), uuid.uuid4()]}
319+
share_response = {'ids': [uuid.uuid4(), uuid.uuid4()]}
320+
321+
# When
322+
# This is equivalent to team.dataset_ids, team.module_ids, etc.
323+
resource_listing = getattr(team, method)
324+
session.set_response(read_response)
325+
readable_ids = resource_listing.list_readable()
326+
session.set_response(write_response)
327+
writeable_ids = resource_listing.list_writeable()
328+
session.set_response(share_response)
329+
shareable_ids = resource_listing.list_shareable()
330+
331+
with pytest.raises(AttributeError):
332+
setattr(team, method, [])
333+
334+
# Then
335+
assert session.num_calls == 3
336+
assert session.calls[0] == FakeCall(method='GET',
337+
path=f'/{resource_type.value}/authorized-ids',
338+
params={"domain": f"/teams/{team.uid}", "action": READ})
339+
assert session.calls[1] == FakeCall(method='GET',
340+
path=f'/{resource_type.value}/authorized-ids',
341+
params={"domain": f"/teams/{team.uid}", "action": WRITE})
342+
assert session.calls[2] == FakeCall(method='GET',
343+
path=f'/{resource_type.value}/authorized-ids',
344+
params={"domain": f"/teams/{team.uid}", "action": SHARE})
345+
assert readable_ids == read_response['ids']
346+
assert writeable_ids == write_response['ids']
347+
assert shareable_ids == share_response['ids']

0 commit comments

Comments
 (0)