Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4134,6 +4134,113 @@ client.create_model_monitoring_request_results(
)
```

## Workspace User

### Get workspace users

Returns a list of internal workspace users. (Up to 20 at a time by default)
Each user includes its granted module permissions in `functionResourcePermissions`.

```python
import fastlabel
client = fastlabel.Client()

users = client.get_workspace_users(
keyword="", # Search keyword for name or email (Optional)
offset=0, # The starting position number to fetch (Optional)
limit=20, # The max number to fetch (Optional, default 20)
)
# [
# {
# "id": "...",
# "userId": "...",
# "userSlug": "...",
# "userName": "John Doe",
# "userEmail": "john@example.com",
# "role": "member",
# "isExternal": False,
# "createdAt": "...",
# "updatedAt": "...",
# "functionResourcePermissions": {
# "annotation": True,
# "modelDev": False,
# "dataset": False
# }
# }
# ]
```

### Create workspace user

Creates an internal workspace user. The `slug` is generated automatically on the server side.
Module permissions are managed separately (see below).

```python
user = client.create_workspace_user(
name="John Doe",
email="john@example.com",
language="en", # 'en' or 'ja'
role="member", # 'member' or 'owner'
)
```

### Update workspace user

Updates an internal workspace user. Only the `role` can be changed.

```python
user = client.update_workspace_user(
id="YOUR_WORKSPACE_USER_ID",
role="owner", # 'member' or 'owner' (Optional)
)
```

### Delete workspace user

Deletes an internal workspace user.

```python
client.delete_workspace_user(id="YOUR_WORKSPACE_USER_ID")
```

### Grant module permissions

Grants module permissions to an internal workspace user.
`modules` accepts a single module or a list (each is sent as a separate request).

```python
# Single module
client.create_workspace_user_module_permissions(
workspace_user_id="YOUR_WORKSPACE_USER_ID",
modules="annotation", # 'annotation', 'modelDev' or 'dataset'
)

# Multiple modules
client.create_workspace_user_module_permissions(
workspace_user_id="YOUR_WORKSPACE_USER_ID",
modules=["annotation", "dataset"],
)
```

### Revoke module permissions

Revokes module permissions from an internal workspace user.
`modules` accepts a single module or a list (each is sent as a separate request).

```python
# Single module
client.delete_workspace_user_module_permissions(
workspace_user_id="YOUR_WORKSPACE_USER_ID",
modules="annotation", # 'annotation', 'modelDev' or 'dataset'
)

# Multiple modules
client.delete_workspace_user_module_permissions(
workspace_user_id="YOUR_WORKSPACE_USER_ID",
modules=["annotation", "dataset"],
)
```

## API Docs

Check [this](https://api.fastlabel.ai/docs/) for further information.
134 changes: 134 additions & 0 deletions fastlabel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5471,6 +5471,140 @@ def get_project_comments(
params["limit"] = limit
return self.api.get_request(endpoint, params=params)

def get_workspace_users(
self,
keyword: str = None,
offset: int = None,
limit: int = 20,
) -> list:
"""
Returns a list of internal workspace users.
keyword is a search keyword for name or email (Optional).
offset is the starting position number to fetch (Optional).
limit is the max number to fetch (Optional, default 20).
"""
endpoint = "workspaces-users"
params = {}
if keyword:
params["keyword"] = keyword
if offset is not None:
params["offset"] = offset
if limit is not None:
params["limit"] = limit
return self.api.get_request(endpoint, params=params)

def create_workspace_user(
self,
name: str,
email: str,
language: str,
role: str,
) -> dict:
"""
Creates an internal workspace user and returns the created user.
name is the user's name (Required).
email is the user's email address (Required).
language is the user's language, 'en' or 'ja' (Required).
role is the workspace role, 'member' or 'owner' (Required).
Module permissions are managed separately; use
create_workspace_user_module_permission to grant them.
"""
endpoint = "workspaces-users/internal-users"
payload = {
"name": name,
"email": email,
"language": language,
"role": role,
}
return self.api.post_request(endpoint, payload=payload)

def update_workspace_user(
self,
id: str,
role: str = None,
) -> dict:
"""
Updates an internal workspace user and returns the updated user.
Only the role can be changed.
id is the id of the workspace user (Required).
role is the workspace role, 'member' or 'owner' (Optional).
"""
endpoint = f"workspaces-users/internal-users/{id}"
payload = {}
if role:
payload["role"] = role
return self.api.put_request(endpoint, payload=payload)

def delete_workspace_user(self, id: str) -> None:
"""
Deletes an internal workspace user.
id is the id of the workspace user (Required).
"""
endpoint = f"workspaces-users/internal-users/{id}"
self.api.delete_request(endpoint)

def create_workspace_user_module_permissions(
self,
workspace_user_id: str,
modules: Union[str, List[str]],
) -> List[str]:
"""
Grants module permissions to an internal workspace user.
Each module is granted with a separate request; if one fails (e.g. the
module user limit is reached), the permissions granted before it remain.
workspace_user_id is the id of the workspace user (Required).
modules is a single module or a list of modules, each one of
'annotation', 'modelDev', 'dataset' (Required).
"""
if isinstance(modules, str):
modules = [modules]
module_paths = {
"annotation": "annotation",
"dataset": "dataset",
"modelDev": "model-dev",
}
results = []
for module in modules:
if module not in module_paths:
raise FastLabelInvalidException(
"module must be one of 'annotation', 'modelDev', 'dataset'.", 422
)
endpoint = (
f"function-resource-permissions/{module_paths[module]}/internal-users"
)
results.append(
self.api.post_request(
endpoint, payload={"workspaceUserId": workspace_user_id}
)
)
return results

def delete_workspace_user_module_permissions(
self,
workspace_user_id: str,
modules: Union[str, List[str]],
) -> None:
"""
Revokes module permissions from an internal workspace user.
Each module is revoked with a separate request; if one fails, the
permissions revoked before it remain revoked.
workspace_user_id is the id of the workspace user (Required).
modules is a single module or a list of modules, each one of
'annotation', 'modelDev', 'dataset' (Required).
"""
if isinstance(modules, str):
modules = [modules]
endpoint = "function-resource-permissions"
for module in modules:
if module not in ("annotation", "modelDev", "dataset"):
raise FastLabelInvalidException(
"module must be one of 'annotation', 'modelDev', 'dataset'.", 422
)
self.api.delete_request(
endpoint,
payload={"workspaceUserId": workspace_user_id, "resource": module},
)

def mask_to_fastlabel_segmentation_points(
self, mask_image: Union[str, np.ndarray]
) -> List[List[List[int]]]:
Expand Down
6 changes: 4 additions & 2 deletions fastlabel/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def get_request(self, endpoint: str, params=None) -> Union[dict, list]:
else:
raise FastLabelException(error, r.status_code)

def delete_request(self, endpoint: str, params=None) -> dict:
def delete_request(self, endpoint: str, params=None, payload=None) -> dict:
"""Makes a delete request to an endpoint.
If an error occurs, assumes that endpoint returns JSON as:
{ 'statusCode': XXX,
Expand All @@ -55,7 +55,9 @@ def delete_request(self, endpoint: str, params=None) -> dict:
"Content-Type": "application/json",
"Authorization": self.access_token,
}
r = requests.delete(self.base_url + endpoint, headers=headers, params=params)
r = requests.delete(
self.base_url + endpoint, headers=headers, params=params, json=payload
)

if r.status_code == 200 or r.status_code == 204:
return
Expand Down
6 changes: 5 additions & 1 deletion fastlabel/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
class FastLabelException(Exception):
def __init__(self, message, errcode):
def __init__(self, message, errcode=None):
super(FastLabelException, self).__init__(
"<Response [{}]> {}".format(errcode, message)
)
self.message = message
self.code = errcode

def __reduce__(self):
return (self.__class__, (self.message, self.code))


class FastLabelInvalidException(FastLabelException, ValueError):
pass
Loading
Loading