dataroom-client 1.0.6.post79.dev0__tar.gz → 1.0.6.post149.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/PKG-INFO +1 -1
- {dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/dataroom_client/client.py +199 -0
- {dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/pyproject.toml +1 -1
- {dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/README.md +0 -0
- {dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/dataroom_client/__init__.py +0 -0
- {dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/dataroom_client/counter.py +0 -0
- {dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/dataroom_client/loader.py +0 -0
- {dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/dataroom_client/print_utils.py +0 -0
{dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/dataroom_client/client.py
RENAMED
|
@@ -353,6 +353,9 @@ class DataRoomClient:
|
|
|
353
353
|
datasets__all: list = None,
|
|
354
354
|
datasets__ne_all: list = None,
|
|
355
355
|
datasets__empty: bool = None,
|
|
356
|
+
group_ids: list[str] = None,
|
|
357
|
+
roles: list[str] = None,
|
|
358
|
+
group_type: str = None,
|
|
356
359
|
) -> list[dict]:
|
|
357
360
|
"""
|
|
358
361
|
Retrieves a paginated list of images, with optional filtering and field selection.
|
|
@@ -437,6 +440,9 @@ class DataRoomClient:
|
|
|
437
440
|
"datasets__all": ",".join(datasets__all) if datasets__all else None,
|
|
438
441
|
"datasets__ne_all": ",".join(datasets__ne_all) if datasets__ne_all else None,
|
|
439
442
|
"datasets__empty": datasets__empty,
|
|
443
|
+
"group_ids": ",".join(group_ids) if group_ids else None,
|
|
444
|
+
"roles": ",".join(roles) if roles else None,
|
|
445
|
+
"group_type": group_type,
|
|
440
446
|
}
|
|
441
447
|
),
|
|
442
448
|
headers=headers,
|
|
@@ -1799,6 +1805,199 @@ class DataRoomClient:
|
|
|
1799
1805
|
method="DELETE",
|
|
1800
1806
|
)
|
|
1801
1807
|
|
|
1808
|
+
# ------------------------------------------------------------------
|
|
1809
|
+
# Roles, GroupTypes, Groups + memberships
|
|
1810
|
+
#
|
|
1811
|
+
# Setup flow when starting from an empty DB:
|
|
1812
|
+
# 1. ``create_role(name)`` for each allowed role
|
|
1813
|
+
# 2. ``create_group_type(name, roles=[{role, is_required}, ...])``
|
|
1814
|
+
# with admin credentials
|
|
1815
|
+
# 3. ``create_group(name, type=...)`` then ``replace_group(...)`` to
|
|
1816
|
+
# attach memberships
|
|
1817
|
+
# All four (Roles, GroupTypes, Groups, Memberships) are open to any
|
|
1818
|
+
# token-authenticated dataroom user.
|
|
1819
|
+
# Group ids are plain UUIDs in Postgres; the type is its own column.
|
|
1820
|
+
# Membership rows carry a canonical role plus free-form metadata.
|
|
1821
|
+
# ------------------------------------------------------------------
|
|
1822
|
+
async def get_roles(self, limit: int = 1000) -> list[dict]:
|
|
1823
|
+
"""Lists all roles."""
|
|
1824
|
+
return await self._make_paginated_request(url="roles/", limit=limit)
|
|
1825
|
+
|
|
1826
|
+
async def create_role(self, name: str, description: str = None) -> dict:
|
|
1827
|
+
"""Creates a role. Roles are referenced by name from GroupTypeRole rows."""
|
|
1828
|
+
payload = self._dict_filter_none({"name": name, "description": description})
|
|
1829
|
+
return await self._make_request(url="roles/", method="POST", json=payload)
|
|
1830
|
+
|
|
1831
|
+
async def delete_role(self, name: str) -> None:
|
|
1832
|
+
"""Deletes a role. Fails if any GroupTypeRole still references it."""
|
|
1833
|
+
return await self._make_request(url=f"roles/{name}/", method="DELETE")
|
|
1834
|
+
|
|
1835
|
+
async def get_group_types(self, limit: int = 1000) -> list[dict]:
|
|
1836
|
+
"""Lists all GroupTypes with their (role, is_required) pairs."""
|
|
1837
|
+
return await self._make_paginated_request(url="group-types/", limit=limit)
|
|
1838
|
+
|
|
1839
|
+
async def get_group_type(self, name: str) -> dict:
|
|
1840
|
+
"""Retrieves a single GroupType by name."""
|
|
1841
|
+
return await self._make_request(url=f"group-types/{name}/", method="GET")
|
|
1842
|
+
|
|
1843
|
+
async def create_group_type(
|
|
1844
|
+
self,
|
|
1845
|
+
name: str,
|
|
1846
|
+
roles: list[dict] = None,
|
|
1847
|
+
description: str = None,
|
|
1848
|
+
metadata_schema: dict = None,
|
|
1849
|
+
) -> dict:
|
|
1850
|
+
"""Creates a GroupType.
|
|
1851
|
+
|
|
1852
|
+
@param name: lowercase alphanumeric/underscore; doubles as the OS-encoding
|
|
1853
|
+
prefix (``<name>::<uuid>``).
|
|
1854
|
+
@param roles: list of ``{"role": <existing role name>, "is_required": bool}``.
|
|
1855
|
+
Roles must already exist — create them with ``create_role`` first.
|
|
1856
|
+
@param description: optional free-form description.
|
|
1857
|
+
@param metadata_schema: JSON Schema applied to ``Group.metadata`` for groups
|
|
1858
|
+
of this type.
|
|
1859
|
+
"""
|
|
1860
|
+
payload = self._dict_filter_none({
|
|
1861
|
+
"name": name,
|
|
1862
|
+
"description": description,
|
|
1863
|
+
"metadata_schema": metadata_schema,
|
|
1864
|
+
"roles": roles,
|
|
1865
|
+
})
|
|
1866
|
+
return await self._make_request(url="group-types/", method="POST", json=payload)
|
|
1867
|
+
|
|
1868
|
+
# No update_group_type: GroupTypes are immutable. A type's name is baked
|
|
1869
|
+
# into the OS encoding of its groups and its schema/roles gate their
|
|
1870
|
+
# validation, so the server rejects PUT/PATCH on group-types. Create a new
|
|
1871
|
+
# type (and migrate) instead.
|
|
1872
|
+
|
|
1873
|
+
async def delete_group_type(self, name: str) -> None:
|
|
1874
|
+
"""Deletes a GroupType. Fails if any Group of this type exists."""
|
|
1875
|
+
return await self._make_request(url=f"group-types/{name}/", method="DELETE")
|
|
1876
|
+
|
|
1877
|
+
async def get_groups(
|
|
1878
|
+
self,
|
|
1879
|
+
type: str = None,
|
|
1880
|
+
search: str = None,
|
|
1881
|
+
limit: int = 1000,
|
|
1882
|
+
) -> list[dict]:
|
|
1883
|
+
"""
|
|
1884
|
+
Lists groups, optionally filtered by type or text search on name/id.
|
|
1885
|
+
|
|
1886
|
+
@param type: Optional group type filter (a GroupType.name).
|
|
1887
|
+
@param search: Optional substring search over name and id.
|
|
1888
|
+
@param limit: Maximum number of groups to return.
|
|
1889
|
+
@return: List of group dicts.
|
|
1890
|
+
"""
|
|
1891
|
+
params = self._dict_filter_none({"type": type, "search": search})
|
|
1892
|
+
return await self._make_paginated_request(url="groups/", params=params, limit=limit)
|
|
1893
|
+
|
|
1894
|
+
async def get_group(self, group_id: str, include_members: bool = False) -> dict:
|
|
1895
|
+
"""
|
|
1896
|
+
Retrieves a single group by id.
|
|
1897
|
+
|
|
1898
|
+
@param group_id: Group UUID.
|
|
1899
|
+
@param include_members: When True, also fetch the group's memberships
|
|
1900
|
+
(a second request to the members endpoint, which is paginated and
|
|
1901
|
+
not part of the group representation) and attach them under a
|
|
1902
|
+
``members`` key as ``[{image_id, role, metadata}, ...]`` — the
|
|
1903
|
+
shape ``upsert_group`` accepts, so a fetched group round-trips
|
|
1904
|
+
without silently dropping members.
|
|
1905
|
+
@return: Group dict (with ``members`` when ``include_members``).
|
|
1906
|
+
"""
|
|
1907
|
+
group = await self._make_request(url=f"groups/{group_id}/", method="GET")
|
|
1908
|
+
if include_members:
|
|
1909
|
+
group["members"] = [
|
|
1910
|
+
{"image_id": m["image_id"], "role": m["role"], "metadata": m.get("metadata", {})}
|
|
1911
|
+
for m in await self.get_group_members(group_id)
|
|
1912
|
+
]
|
|
1913
|
+
return group
|
|
1914
|
+
|
|
1915
|
+
async def update_group(
|
|
1916
|
+
self,
|
|
1917
|
+
group_id: str,
|
|
1918
|
+
name: str = None,
|
|
1919
|
+
description: str = None,
|
|
1920
|
+
metadata: dict = None,
|
|
1921
|
+
cover_image_id: str = None,
|
|
1922
|
+
) -> dict:
|
|
1923
|
+
"""
|
|
1924
|
+
Partially updates a group. The `type` is immutable and cannot be changed.
|
|
1925
|
+
|
|
1926
|
+
@param group_id: Group UUID.
|
|
1927
|
+
@return: Updated group dict.
|
|
1928
|
+
"""
|
|
1929
|
+
payload = self._dict_filter_none({
|
|
1930
|
+
"name": name,
|
|
1931
|
+
"description": description,
|
|
1932
|
+
"metadata": metadata,
|
|
1933
|
+
"cover_image_id": cover_image_id,
|
|
1934
|
+
})
|
|
1935
|
+
return await self._make_request(
|
|
1936
|
+
url=f"groups/{group_id}/",
|
|
1937
|
+
method="PATCH",
|
|
1938
|
+
json=payload,
|
|
1939
|
+
)
|
|
1940
|
+
|
|
1941
|
+
async def delete_group(self, group_id: str) -> None:
|
|
1942
|
+
"""
|
|
1943
|
+
Soft-deletes a group and queues the OS scrub. The Postgres row is
|
|
1944
|
+
finalized by the reconciler once OS is clean.
|
|
1945
|
+
"""
|
|
1946
|
+
return await self._make_request(url=f"groups/{group_id}/", method="DELETE")
|
|
1947
|
+
|
|
1948
|
+
async def get_group_members(self, group_id: str, limit: int = 1000) -> list[dict]:
|
|
1949
|
+
"""
|
|
1950
|
+
Lists memberships of a group.
|
|
1951
|
+
|
|
1952
|
+
@return: List of {id, image_id, role, metadata, ...}.
|
|
1953
|
+
"""
|
|
1954
|
+
return await self._make_paginated_request(url=f"groups/{group_id}/members/", limit=limit)
|
|
1955
|
+
|
|
1956
|
+
async def upsert_group(
|
|
1957
|
+
self,
|
|
1958
|
+
name: str,
|
|
1959
|
+
type: str,
|
|
1960
|
+
metadata: dict = None,
|
|
1961
|
+
members: list[dict] = None,
|
|
1962
|
+
description: str = None,
|
|
1963
|
+
cover_image_id: str = None,
|
|
1964
|
+
group_id: str = None,
|
|
1965
|
+
) -> dict:
|
|
1966
|
+
"""Create-or-replace a group by name. One PUT round-trip in the common case.
|
|
1967
|
+
|
|
1968
|
+
Re-running the same call with the same ``name`` is idempotent: the client
|
|
1969
|
+
looks up an existing group with that name (or uses the explicit ``group_id``
|
|
1970
|
+
when supplied), and PUTs the whole ``{metadata, members}`` payload to its
|
|
1971
|
+
UUID. New groups get a fresh UUID4 generated client-side and committed via
|
|
1972
|
+
the same PUT. The server validates roles + metadata in one transaction.
|
|
1973
|
+
"""
|
|
1974
|
+
import uuid as _uuid
|
|
1975
|
+
|
|
1976
|
+
if group_id is None:
|
|
1977
|
+
matches = [g for g in await self.get_groups(search=name) if g['name'] == name]
|
|
1978
|
+
group_id = matches[0]['id'] if matches else str(_uuid.uuid4())
|
|
1979
|
+
|
|
1980
|
+
payload = self._dict_filter_none({
|
|
1981
|
+
"name": name,
|
|
1982
|
+
"type": type,
|
|
1983
|
+
"metadata": metadata if metadata is not None else {},
|
|
1984
|
+
"members": members if members is not None else [],
|
|
1985
|
+
"description": description,
|
|
1986
|
+
"cover_image_id": cover_image_id,
|
|
1987
|
+
})
|
|
1988
|
+
return await self._make_request(
|
|
1989
|
+
url=f"groups/{group_id}/",
|
|
1990
|
+
method="PUT",
|
|
1991
|
+
json=payload,
|
|
1992
|
+
)
|
|
1993
|
+
|
|
1994
|
+
async def get_image_groups(self, image_id: str) -> list[dict]:
|
|
1995
|
+
"""
|
|
1996
|
+
Lists all (non-deleted) groups this image is a member of, hydrated.
|
|
1997
|
+
|
|
1998
|
+
Each item: {group: {...}, role, metadata}.
|
|
1999
|
+
"""
|
|
2000
|
+
return await self._make_request(url=f"images/{image_id}/groups/", method="GET")
|
|
1802
2001
|
|
|
1803
2002
|
|
|
1804
2003
|
class AsyncRunner:
|
|
File without changes
|
{dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/dataroom_client/__init__.py
RENAMED
|
File without changes
|
{dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/dataroom_client/counter.py
RENAMED
|
File without changes
|
{dataroom_client-1.0.6.post79.dev0 → dataroom_client-1.0.6.post149.dev0}/dataroom_client/loader.py
RENAMED
|
File without changes
|
|
File without changes
|