Skip to content

Commit

Permalink
Add organization context support to high-level API
Browse files Browse the repository at this point in the history
  • Loading branch information
SpecLad committed Feb 16, 2023
1 parent 87d8d98 commit 6dcb4ff
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 2 deletions.
22 changes: 22 additions & 0 deletions cvat-sdk/cvat_sdk/core/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,28 @@ def __init__(
self._repos: Dict[str, Repo] = {}
"""A cache for created Repository instances"""

_ORG_SLUG_HEADER = "X-Organization"

@property
def current_organization(self) -> Optional[str]:
"""
If this is set to a slug for an organization,
all requests will be made in the context of that organization.
If it's set to an empty string, requests will be made in the context
of the user's personal workspace.
If set to None (the default), no organization context will be used.
"""
return self.api_client.default_headers.get(self._ORG_SLUG_HEADER)

@current_organization.setter
def current_organization(self, org_slug: Optional[str]):
if org_slug is None:
self.api_client.default_headers.pop(self._ORG_SLUG_HEADER, None)
else:
self.api_client.default_headers[self._ORG_SLUG_HEADER] = org_slug

ALLOWED_SCHEMAS = ("https", "http")

@classmethod
Expand Down
16 changes: 15 additions & 1 deletion site/content/en/docs/api_sdk/sdk/highlevel-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,24 @@ an error can be raised or suppressed (controlled by `config.allow_unsupported_se
If the error is suppressed, some SDK functions may not work as expected with this server.
By default, a warning is raised and the error is suppressed.

> Please note that all `Client` operations rely on the server API and depend on the current user
### Users and organizations

All `Client` operations rely on the server API and depend on the current user
rights. This affects the set of available APIs, objects and actions. For example, a regular user
can only see and modify their tasks and jobs, while an admin user can see all the tasks etc.

Operations are also affected by the current organization context,
which can be set with the `current_organization` property of `Client` instances.
The organization context affects which entities are visible,
and where new entities are created.

Set `current_organization` to an organization's slug (short name)
to make subsequent operations work in the context of that organization.
Set it to an empty string to work in the context of the user's personal workspace.
By default, it is set to `None`,
which means that both personal and organizational entities are visible,
while new entities are created in the personal workspace.

## Entities and Repositories

_Entities_ represent objects on the server. They provide read access to object fields
Expand Down
37 changes: 36 additions & 1 deletion tests/python/sdk/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

import packaging.version as pv
import pytest
from cvat_sdk import Client
from cvat_sdk import Client, models
from cvat_sdk.api_client.exceptions import NotFoundException
from cvat_sdk.core.client import Config, make_client
from cvat_sdk.core.exceptions import IncompatibleVersionException, InvalidHostException
from cvat_sdk.exceptions import ApiException
Expand Down Expand Up @@ -166,3 +167,37 @@ def test_can_control_ssl_verification_with_config(verify: bool):
client = Client(BASE_URL, config=config)

assert client.api_client.configuration.verify_ssl == verify


def test_organization_contexts(admin_user: str):
with make_client(BASE_URL, credentials=(admin_user, USER_PASS)) as client:
assert client.current_organization is None

org = client.organizations.create(models.OrganizationWriteRequest(slug="testorg"))

# create a project in the personal workspace
client.current_organization = ""
personal_project = client.projects.create(models.ProjectWriteRequest(name="Personal"))
assert personal_project.organization is None

# create a project in the organization
client.current_organization = org.slug
org_project = client.projects.create(models.ProjectWriteRequest(name="Org"))
assert org_project.organization == org.id

# both projects should be visible with no context
client.current_organization = None
client.projects.retrieve(personal_project.id)
client.projects.retrieve(org_project.id)

# only the personal project should be visible in the personal workspace
client.current_organization = ""
client.projects.retrieve(personal_project.id)
with pytest.raises(NotFoundException):
client.projects.retrieve(org_project.id)

# only the organizational project should be visible in the organization
client.current_organization = org.slug
client.projects.retrieve(org_project.id)
with pytest.raises(NotFoundException):
client.projects.retrieve(personal_project.id)

0 comments on commit 6dcb4ff

Please sign in to comment.