Skip to content
Merged
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
11 changes: 11 additions & 0 deletions gooddata-sdk/gooddata_sdk/catalog/identifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from gooddata_metadata_client.model.assignee_identifier import AssigneeIdentifier
from gooddata_metadata_client.model.grain_identifier import GrainIdentifier
from gooddata_metadata_client.model.reference_identifier import ReferenceIdentifier
from gooddata_metadata_client.model.user_group_identifier import UserGroupIdentifier
from gooddata_metadata_client.model.workspace_identifier import WorkspaceIdentifier
from gooddata_sdk.catalog.base import Base

Expand Down Expand Up @@ -48,3 +49,13 @@ class CatalogAssigneeIdentifier(Base):
@staticmethod
def client_class() -> Type[AssigneeIdentifier]:
return AssigneeIdentifier


@attr.s(auto_attribs=True, kw_only=True)
class CatalogUserGroupIdentifier(Base):
id: str
type: str = "userGroup"

@staticmethod
def client_class() -> Type[UserGroupIdentifier]:
return UserGroupIdentifier
1 change: 1 addition & 0 deletions gooddata-sdk/gooddata_sdk/catalog/user/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# (C) 2022 GoodData Corporation
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# (C) 2022 GoodData Corporation
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# (C) 2022 GoodData Corporation
from __future__ import annotations

from pathlib import Path
from typing import List, Optional, Type

import attr

from gooddata_metadata_client.model.declarative_user import DeclarativeUser
from gooddata_metadata_client.model.declarative_users import DeclarativeUsers
from gooddata_sdk.catalog.base import Base
from gooddata_sdk.catalog.identifier import CatalogUserGroupIdentifier
from gooddata_sdk.utils import create_directory, get_sorted_yaml_files, read_layout_from_file, write_layout_to_file

LAYOUT_USERS_DIR = "users"


@attr.s(auto_attribs=True, kw_only=True)
class CatalogDeclarativeUsers(Base):
users: List[CatalogDeclarativeUser]

@staticmethod
def client_class() -> Type[DeclarativeUsers]:
return DeclarativeUsers

@classmethod
def load_from_disk(cls, layout_organization_folder: Path) -> CatalogDeclarativeUsers:
users_directory = layout_organization_folder / LAYOUT_USERS_DIR
user_files = get_sorted_yaml_files(users_directory)
users = []
for user_file in user_files:
users.append(CatalogDeclarativeUser.load_from_disk(user_file))
return cls(users=users)

def store_to_disk(self, layout_organization_folder: Path) -> None:
users_directory = layout_organization_folder / LAYOUT_USERS_DIR
create_directory(users_directory)
for user in self.users:
user.store_to_disk(users_directory)


@attr.s(auto_attribs=True, kw_only=True)
class CatalogDeclarativeUser(Base):
id: str
auth_id: Optional[str] = None
user_groups: List[CatalogUserGroupIdentifier] = []

@staticmethod
def client_class() -> Type[DeclarativeUser]:
return DeclarativeUser

def store_to_disk(self, users_directory: Path) -> None:
user_path = users_directory / f"{self.id}.yaml"
user_data = self.to_dict(camel_case=True)
write_layout_to_file(user_path, user_data)

@classmethod
def load_from_disk(cls, users_directory: Path) -> CatalogDeclarativeUser:
data = read_layout_from_file(users_directory)
return cls.from_dict(data, camel_case=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# (C) 2022 GoodData Corporation
from __future__ import annotations

from pathlib import Path
from typing import List, Optional, Type

import attr

from gooddata_metadata_client.model.declarative_user_group import DeclarativeUserGroup
from gooddata_metadata_client.model.declarative_user_groups import DeclarativeUserGroups
from gooddata_sdk.catalog.base import Base
from gooddata_sdk.catalog.identifier import CatalogUserGroupIdentifier
from gooddata_sdk.utils import create_directory, get_sorted_yaml_files, read_layout_from_file, write_layout_to_file

LAYOUT_USER_GROUPS_DIR = "user_groups"


@attr.s(auto_attribs=True, kw_only=True)
class CatalogDeclarativeUserGroups(Base):
user_groups: List[CatalogDeclarativeUserGroup] = []

@staticmethod
def client_class() -> Type[DeclarativeUserGroups]:
return DeclarativeUserGroups

@classmethod
def load_from_disk(cls, layout_organization_folder: Path) -> CatalogDeclarativeUserGroups:
user_groups_directory = layout_organization_folder / LAYOUT_USER_GROUPS_DIR
user_group_files = get_sorted_yaml_files(user_groups_directory)
user_groups = []
for user_group_file in user_group_files:
user_groups.append(CatalogDeclarativeUserGroup.load_from_disk(user_group_file))
return cls(user_groups=user_groups)

def store_to_disk(self, layout_organization_folder: Path) -> None:
user_groups_directory = layout_organization_folder / LAYOUT_USER_GROUPS_DIR
create_directory(user_groups_directory)
for user_group in self.user_groups:
user_group.store_to_disk(user_groups_directory)


@attr.s(auto_attribs=True, kw_only=True)
class CatalogDeclarativeUserGroup(Base):
id: str
parents: Optional[List[CatalogUserGroupIdentifier]] = None

@staticmethod
def client_class() -> Type[DeclarativeUserGroup]:
return DeclarativeUserGroup

def store_to_disk(self, user_groups_directory: Path) -> None:
user_group_path = user_groups_directory / f"{self.id}.yaml"
user_data = self.to_dict(camel_case=True)
write_layout_to_file(user_group_path, user_data)

@classmethod
def load_from_disk(cls, user_groups_directory: Path) -> CatalogDeclarativeUserGroup:
data = read_layout_from_file(user_groups_directory)
return cls.from_dict(data, camel_case=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# (C) 2022 GoodData Corporation
71 changes: 71 additions & 0 deletions gooddata-sdk/gooddata_sdk/catalog/user/entity_model/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# (C) 2022 GoodData Corporation
from __future__ import annotations

from typing import List, Optional, Type

import attr

from gooddata_metadata_client.model.json_api_user_in import JsonApiUserIn
from gooddata_metadata_client.model.json_api_user_in_document import JsonApiUserInDocument
from gooddata_sdk.catalog.base import Base
from gooddata_sdk.catalog.user.entity_model.user_group import CatalogUserGroup


@attr.s(auto_attribs=True, kw_only=True)
class CatalogUserDocument(Base):
data: CatalogUser

@staticmethod
def client_class() -> Type[JsonApiUserInDocument]:
return JsonApiUserInDocument

@classmethod
def create_user(
cls, user_id: str, authentication_id: Optional[str] = None, user_groups: Optional[List[str]] = None
) -> CatalogUserDocument:
attributes = CatalogUserAttributes(authentication_id=authentication_id)
relationships = None
if user_groups is not None:
relationships = CatalogUserRelationships(
user_groups=CatalogUserGroupsData(data=[CatalogUserGroup(id=user_group) for user_group in user_groups])
)
user = CatalogUser(id=user_id, attributes=attributes, relationships=relationships)
return cls(data=user)


@attr.s(auto_attribs=True, kw_only=True)
class CatalogUser(Base):
id: str
attributes: Optional[CatalogUserAttributes] = None
relationships: Optional[CatalogUserRelationships] = None

@staticmethod
def client_class() -> Type[JsonApiUserIn]:
return JsonApiUserIn

@property
def get_user_groups(self) -> Optional[List[str]]:
return self.relationships.get_user_groups if self.relationships is not None else None


@attr.s(auto_attribs=True, kw_only=True)
class CatalogUserAttributes(Base):
authentication_id: Optional[str] = None


@attr.s(auto_attribs=True, kw_only=True)
class CatalogUserRelationships(Base):
user_groups: Optional[CatalogUserGroupsData] = None

@property
def get_user_groups(self) -> Optional[List[str]]:
return self.user_groups.get_user_groups if self.user_groups is not None else None


@attr.s(auto_attribs=True, kw_only=True)
class CatalogUserGroupsData(Base):
data: List[CatalogUserGroup]

@property
def get_user_groups(self) -> Optional[List[str]]:
return [user_group.id for user_group in self.data]
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# (C) 2022 GoodData Corporation
from __future__ import annotations

from typing import List, Optional, Type

import attr

from gooddata_metadata_client.model.json_api_user_group_in import JsonApiUserGroupIn
from gooddata_metadata_client.model.json_api_user_group_in_document import JsonApiUserGroupInDocument
from gooddata_sdk.catalog.base import Base


@attr.s(auto_attribs=True, kw_only=True)
class CatalogUserGroupDocument(Base):
data: CatalogUserGroup

@staticmethod
def client_class() -> Type[JsonApiUserGroupInDocument]:
return JsonApiUserGroupInDocument

@classmethod
def create_user_group(
cls, user_group_id: str, user_group_parents_id: Optional[List[str]] = None
) -> CatalogUserGroupDocument:
relationships = None
if user_group_parents_id is not None:
relationships = CatalogUserGroupRelationships(
parents=CatalogUserGroupParents(
data=[CatalogUserGroup(id=user_group_parent_id) for user_group_parent_id in user_group_parents_id]
)
)
return cls(data=CatalogUserGroup(id=user_group_id, relationships=relationships))


@attr.s(auto_attribs=True, kw_only=True)
class CatalogUserGroup(Base):
id: str
relationships: Optional[CatalogUserGroupRelationships] = None

@staticmethod
def client_class() -> Type[JsonApiUserGroupIn]:
return JsonApiUserGroupIn


@attr.s(auto_attribs=True, kw_only=True)
class CatalogUserGroupRelationships(Base):
parents: Optional[CatalogUserGroupParents] = None


@attr.s(auto_attribs=True, kw_only=True)
class CatalogUserGroupParents(Base):
data: Optional[List[CatalogUserGroup]] = None
97 changes: 97 additions & 0 deletions gooddata-sdk/gooddata_sdk/catalog/user/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# (C) 2022 GoodData Corporation
from __future__ import annotations

import functools
from pathlib import Path
from typing import List, Optional

from gooddata_sdk.catalog.catalog_service_base import CatalogServiceBase
from gooddata_sdk.catalog.user.declarative_model.user import CatalogDeclarativeUsers
from gooddata_sdk.catalog.user.declarative_model.user_group import CatalogDeclarativeUserGroups
from gooddata_sdk.catalog.user.entity_model.user import CatalogUser, CatalogUserDocument
from gooddata_sdk.catalog.user.entity_model.user_group import CatalogUserGroup, CatalogUserGroupDocument
from gooddata_sdk.utils import load_all_entities, load_all_entities_dict


class CatalogUserService(CatalogServiceBase):
def list_users(self) -> List[CatalogUser]:
get_users = functools.partial(
self._entities_api.get_all_entities_users,
include=["userGroups"],
_check_return_type=False,
)
users = load_all_entities_dict(get_users, camel_case=False)
Comment thread
jaceksan marked this conversation as resolved.
return [CatalogUser.from_dict(v, camel_case=False) for v in users["data"]]

def list_user_groups(self) -> List[CatalogUserGroup]:
get_user_groups = functools.partial(
self._entities_api.get_all_entities_user_groups,
include=["userGroups"],
_check_return_type=False,
)
user_groups = load_all_entities(get_user_groups)
return [CatalogUserGroup.from_api(v) for v in user_groups.data]

def get_user(self, user_id: str) -> CatalogUser:
user_dict = self._entities_api.get_entity_users(id=user_id, include=["userGroups"]).data.to_dict(
camel_case=False
)
return CatalogUser.from_dict(user_dict, camel_case=False)

def create_user(
self, user_id: str, authentication_id: Optional[str] = None, user_groups: Optional[list[str]] = None
) -> None:
user_document = CatalogUserDocument.create_user(user_id, authentication_id, user_groups)
Comment thread
jaceksan marked this conversation as resolved.
self._entities_api.create_entity_users(json_api_user_in_document=user_document.to_api())

def delete_user(self, user_id: str) -> None:
self._entities_api.delete_entity_users(id=user_id)

def get_user_group(self, user_group_id: str) -> CatalogUserGroup:
user_group = self._entities_api.get_entity_user_groups(id=user_group_id, include=["ALL"]).data.to_dict(
camel_case=False
)
return CatalogUserGroup.from_dict(user_group, camel_case=False)

def create_user_group(self, user_group_id: str, user_group_parents_id: Optional[List[str]] = None) -> None:
user_group_document = CatalogUserGroupDocument.create_user_group(
user_group_id=user_group_id, user_group_parents_id=user_group_parents_id
)
self._entities_api.create_entity_user_groups(user_group_document.to_api())

def delete_user_group(self, user_group_id: str) -> None:
self._entities_api.delete_entity_user_groups(id=user_group_id)

# Declarative methods for User service are listed below

def get_declarative_users(self) -> CatalogDeclarativeUsers:
return CatalogDeclarativeUsers.from_api(self._layout_api.get_users_layout())

def get_declarative_user_groups(self) -> CatalogDeclarativeUserGroups:
return CatalogDeclarativeUserGroups.from_api(self._layout_api.get_user_groups_layout())

def put_declarative_users(self, users: CatalogDeclarativeUsers) -> None:
self._layout_api.put_users_layout(users.to_api())

def put_declarative_user_groups(self, user_groups: CatalogDeclarativeUserGroups) -> None:
self._layout_api.put_user_groups_layout(user_groups.to_api())

def load_declarative_users(self, layout_root_path: Path = Path.cwd()) -> CatalogDeclarativeUsers:
return CatalogDeclarativeUsers.load_from_disk(self.layout_organization_folder(layout_root_path))

def load_declarative_user_groups(self, layout_root_path: Path = Path.cwd()) -> CatalogDeclarativeUserGroups:
return CatalogDeclarativeUserGroups.load_from_disk(self.layout_organization_folder(layout_root_path))

def store_declarative_users(self, layout_root_path: Path = Path.cwd()) -> None:
self.get_declarative_users().store_to_disk(self.layout_organization_folder(layout_root_path))

def store_declarative_user_groups(self, layout_root_path: Path = Path.cwd()) -> None:
self.get_declarative_user_groups().store_to_disk(self.layout_organization_folder(layout_root_path))

def load_and_put_declarative_users(self, layout_root_path: Path = Path.cwd()) -> None:
declarative_users = self.load_declarative_users(layout_root_path)
self.put_declarative_users(declarative_users)

def load_and_put_declarative_user_groups(self, layout_root_path: Path = Path.cwd()) -> None:
declarative_user_groups = self.load_declarative_user_groups(layout_root_path)
self.put_declarative_user_groups(declarative_user_groups)
6 changes: 6 additions & 0 deletions gooddata-sdk/gooddata_sdk/sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from gooddata_sdk.catalog.data_source.service import CatalogDataSourceService
from gooddata_sdk.catalog.organization.service import CatalogOrganizationService
from gooddata_sdk.catalog.user.service import CatalogUserService
from gooddata_sdk.catalog.workspace.service import CatalogWorkspaceContentService, CatalogWorkspaceService
from gooddata_sdk.client import GoodDataApiClient
from gooddata_sdk.compute.service import ComputeService
Expand Down Expand Up @@ -47,6 +48,7 @@ def __init__(self, client: GoodDataApiClient) -> None:
self._catalog_workspace_content = CatalogWorkspaceContentService(self._client)
self._catalog_data_source = CatalogDataSourceService(self._client)
self._catalog_organization = CatalogOrganizationService(self._client)
self._catalog_user = CatalogUserService(self._client)
self._compute = ComputeService(self._client)
self._insights = InsightService(self._client)
self._tables = TableService(self._client)
Expand Down Expand Up @@ -83,3 +85,7 @@ def tables(self) -> TableService:
@property
def support(self) -> SupportService:
return self._support

@property
def catalog_user(self) -> CatalogUserService:
return self._catalog_user
Loading