Skip to content

Commit

Permalink
feat: update workspace group
Browse files Browse the repository at this point in the history
Signed-off-by: Youngjin Jo <[email protected]>
  • Loading branch information
yjinjo committed Sep 6, 2024
1 parent 75bf889 commit d03d245
Show file tree
Hide file tree
Showing 9 changed files with 369 additions and 412 deletions.
18 changes: 0 additions & 18 deletions src/spaceone/identity/interface/grpc/workspace_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,6 @@ def delete(self, request, context):
workspace_group_svc.delete(params)
return self.empty()

def add_workspaces(self, request, context):
params, metadata = self.parse_request(request, context)
workspace_group_svc = WorkspaceGroupService(metadata)
response: dict = workspace_group_svc.add_workspaces(params)
return self.dict_to_message(response)

def remove_workspaces(self, request, context):
params, metadata = self.parse_request(request, context)
workspace_group_svc = WorkspaceGroupService(metadata)
response: dict = workspace_group_svc.remove_workspaces(params)
return self.dict_to_message(response)

def find_users(self, request, context):
params, metadata = self.parse_request(request, context)
workspace_group_svc = WorkspaceGroupService(metadata)
response: dict = workspace_group_svc.find_users(params)
return self.dict_to_message(response)

def add_users(self, request, context):
params, metadata = self.parse_request(request, context)
workspace_group_svc = WorkspaceGroupService(metadata)
Expand Down
3 changes: 2 additions & 1 deletion src/spaceone/identity/manager/role_binding_manager.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import logging
from typing import Tuple
from mongoengine import QuerySet

from mongoengine import QuerySet
from spaceone.core.manager import BaseManager

from spaceone.identity.model.role_binding.database import RoleBinding

_LOGGER = logging.getLogger(__name__)
Expand Down
55 changes: 46 additions & 9 deletions src/spaceone/identity/manager/workspace_group_manager.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import logging
from typing import Tuple
from typing import Dict, List, Tuple

from mongoengine import QuerySet
from spaceone.core.error import ERROR_INVALID_PARAMETER, ERROR_NOT_FOUND
from spaceone.core.manager import BaseManager

from spaceone.identity.manager.role_binding_manager import RoleBindingManager
Expand Down Expand Up @@ -51,19 +52,21 @@ def delete_workspace_group_by_vo(self, workspace_group_vo: WorkspaceGroup) -> No

if rb_vos.count() > 0:
_LOGGER.debug(
f"[delete_workspace_group_by_vo] Delete role bindings count with {workspace_group_vo.workspaces}: {rb_vos.count()}"
f"[delete_workspace_group_by_vo] Delete role bindings count with {workspace_group_vo.users}: {rb_vos.count()}"
)
rb_vos.delete()
for rb_vo in rb_vos:
_LOGGER.debug(
f"[delete_workspace_group_by_vo] Delete role binding info: {rb_vo.to_dict()}"
)
rb_vo.delete()

workspace_group_vo.delete()

# TODO: When add_users and remove_users, are user_id and role_type required?
def get_workspace_group(
self,
workspace_group_id: str,
domain_id: str,
user_id: str = None,
role_type: str = None,
) -> WorkspaceGroup:
conditions = {
"workspace_group_id": workspace_group_id,
Expand All @@ -73,10 +76,6 @@ def get_workspace_group(
if user_id:
conditions["users__user_id"] = user_id

# TODO: Check if this is correct
# if role_type:
# conditions["users__role_type"] = role_type

return self.workspace_group_model.get(**conditions)

def filter_workspace_groups(self, **conditions) -> QuerySet:
Expand All @@ -94,3 +93,41 @@ def check_user_id_in_users(user_id: str, workspace_group_vo: WorkspaceGroup):
workspace_group_user_id == user_id
for workspace_group_user_id in workspace_group_vo["users"]
)

def get_old_users_and_new_users(
self, users: List[Dict[str, str]], workspace_group_id: str, domain_id: str
) -> Tuple[List[str], List[str]]:
workspace_group_vo = self.get_workspace_group(workspace_group_id, domain_id)

old_users = list(
set(
[user_info["user_id"] for user_info in workspace_group_vo.users]
if workspace_group_vo.users
else []
)
)
new_users = list(set([user_info["user_id"] for user_info in users]))

return old_users, new_users

@staticmethod
def check_new_users_already_in_workspace_group(
old_users: List[str], new_users: List[str]
) -> None:
if set(old_users) & set(new_users):
_LOGGER.error(
f"Users {new_users} is already in workspace group or not registered."
)
raise ERROR_INVALID_PARAMETER(
key="users",
reason=f"User {new_users} is already in the workspace group or not registered.",
)

@staticmethod
def check_user_ids_exist_in_workspace_group(
old_user_ids: List[str], user_ids: List[str]
) -> None:
for user_id in user_ids:
if user_id not in old_user_ids:
_LOGGER.error(f"User ID {user_id} is not in workspace group.")
raise ERROR_NOT_FOUND(key="user_id", value=user_id)
27 changes: 20 additions & 7 deletions src/spaceone/identity/model/workspace_group/database.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
from mongoengine import DateTimeField, DictField, ListField, StringField
from mongoengine import (
DateTimeField,
DictField,
EmbeddedDocument,
EmbeddedDocumentField,
ListField,
StringField,
)
from spaceone.core.model.mongo_model import MongoModel


class WorkspaceGroupUser(EmbeddedDocument):
user_id = StringField(max_length=40, required=True)
role_id = StringField(max_length=40, required=True)
role_type = StringField(
max_length=20, choices=("WORKSPACE_OWNER", "WORKSPACE_MEMBER")
)


class WorkspaceGroup(MongoModel):
workspace_group_id = StringField(max_length=40, generate_id="wg", unique=True)
name = StringField(max_length=255, unique_with="domain_id")
workspaces = ListField(StringField(max_length=40), default=None, null=True)
users = ListField(DictField(default=None), default=None, null=True)
users = ListField(
EmbeddedDocumentField(WorkspaceGroupUser), default=None, null=True
)
tags = DictField(default=None)
created_by = StringField(max_length=255)
updated_by = StringField(max_length=255)
Expand All @@ -17,7 +33,6 @@ class WorkspaceGroup(MongoModel):
meta = {
"updatable_fields": [
"name",
"workspaces",
"users",
"tags",
"updated_by",
Expand All @@ -27,9 +42,7 @@ class WorkspaceGroup(MongoModel):
"workspace_group_id",
"name",
],
"change_query_keys": {
"workspace_id": "workspaces",
},
"change_query_keys": {},
"ordering": ["name"],
"indexes": [
"workspace_group_id",
Expand Down
16 changes: 0 additions & 16 deletions src/spaceone/identity/model/workspace_group/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
"WorkspaceGroupCreateRequest",
"WorkspaceGroupUpdateRequest",
"WorkspaceGroupDeleteRequest",
"WorkspaceGroupAddWorkspacesRequest",
"WorkspaceGroupRemoveWorkspacesRequest",
"WorkspaceGroupAddUsersRequest",
"WorkspaceGroupRemoveUsersRequest",
"WorkspaceGroupUpdateRoleRequest",
Expand Down Expand Up @@ -41,20 +39,6 @@ class WorkspaceGroupDeleteRequest(BaseModel):
domain_id: str


class WorkspaceGroupAddWorkspacesRequest(BaseModel):
workspace_group_id: str
workspaces: List[str]
workspace_id: Union[str, None] = None
domain_id: str


class WorkspaceGroupRemoveWorkspacesRequest(BaseModel):
workspace_group_id: str
workspaces: List[str]
workspace_id: Union[str, None] = None
domain_id: str


class WorkspaceGroupAddUsersRequest(BaseModel):
workspace_group_id: str
users: List[Dict[str, str]]
Expand Down
13 changes: 10 additions & 3 deletions src/spaceone/identity/model/workspace_group/response.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
from datetime import datetime
from typing import Dict, List, Union
from typing import List, Union

from pydantic.main import BaseModel
from spaceone.core import utils

__all__ = ["WorkspaceGroupResponse", "WorkspaceGroupsResponse"]


class WorkspaceGroupUser(BaseModel):
user_id: str
role_id: str
role_type: str
user_name: Union[str, None] = None
state: Union[str, None] = None


class WorkspaceGroupResponse(BaseModel):
workspace_group_id: Union[str, None] = None
name: Union[str, None] = None
workspaces: Union[list, None] = None
users: Union[List[Dict[str, str]], None] = None
users: Union[List[WorkspaceGroupUser], None] = None
tags: Union[dict, None] = None
created_by: Union[str, None] = None
updated_by: Union[str, None] = None
Expand Down
45 changes: 25 additions & 20 deletions src/spaceone/identity/service/role_binding_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from spaceone.identity.manager.role_manager import RoleManager
from spaceone.identity.manager.user_manager import UserManager
from spaceone.identity.manager.workspace_manager import WorkspaceManager
from spaceone.identity.model import RoleBinding
from spaceone.identity.model.role_binding.request import *
from spaceone.identity.model.role_binding.response import *

Expand Down Expand Up @@ -269,26 +270,7 @@ def delete(self, params: RoleBindingDeleteRequest) -> None:
user_vo = self.user_mgr.get_user(rb_vo.user_id, rb_vo.domain_id)

self.user_mgr.update_user_by_vo(user_role_info, user_vo)
self.role_binding_manager.delete_role_binding_by_vo(rb_vo)

workspace_vo = self.workspace_mgr.get_workspace(
params.workspace_id, params.domain_id
)

user_rb_ids = self.role_binding_manager.stat_role_bindings(
query={
"distinct": "user_id",
"filter": [
{"k": "workspace_id", "v": params.workspace_id, "o": "eq"},
{"k": "domain_id", "v": params.domain_id, "o": "eq"},
],
}
).get("results", [])
user_rb_total_count = len(user_rb_ids)

self.workspace_mgr.update_workspace_by_vo(
{"user_count": user_rb_total_count}, workspace_vo
)
self.delete_role_binding_by_vo(rb_vo, params.domain_id, params.workspace_id)

@transaction(
permission="identity:RoleBinding.read",
Expand Down Expand Up @@ -474,3 +456,26 @@ def _get_latest_role_type(before: str, after: str) -> str:
return "USER"

return after

def delete_role_binding_by_vo(
self, rb_vo: RoleBinding, domain_id: str, workspace_id: str = None
):
self.role_binding_manager.delete_role_binding_by_vo(rb_vo)

if workspace_id:
workspace_vo = self.workspace_mgr.get_workspace(workspace_id, domain_id)

user_rb_ids = self.role_binding_manager.stat_role_bindings(
query={
"distinct": "user_id",
"filter": [
{"k": "workspace_id", "v": workspace_id, "o": "eq"},
{"k": "domain_id", "v": domain_id, "o": "eq"},
],
}
).get("results", [])
user_rb_total_count = len(user_rb_ids)

self.workspace_mgr.update_workspace_by_vo(
{"user_count": user_rb_total_count}, workspace_vo
)
14 changes: 7 additions & 7 deletions src/spaceone/identity/service/token_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ def grant(self, params: TokenGrantRequest) -> Union[GrantTokenResponse, dict]:

# todo: remove
if (
domain_id == SystemManager.get_root_domain_id()
and params.scope == "WORKSPACE"
domain_id == SystemManager.get_root_domain_id()
and params.scope == "WORKSPACE"
):
public_jwk = self.domain_secret_mgr.get_domain_public_key(domain_id)
domain_id = params.domain_id
Expand Down Expand Up @@ -317,7 +317,7 @@ def _verify_token(grant_type: str, token: str, public_jwk: dict) -> dict:
return token_info

def _get_user_role_info(
self, user_vo: User, workspace_id: str = None
self, user_vo: User, workspace_id: str = None
) -> Tuple[str, Union[str, None]]:
if user_vo.role_type == "DOMAIN_ADMIN":
rb_vos = self.rb_mgr.filter_role_bindings(
Expand Down Expand Up @@ -357,13 +357,13 @@ def _get_app_role_info(app_vo: App) -> Tuple[str, str]:
key="identity:role-permissions-page-access:{domain_id}:{role_id}", expire=600
)
def _get_role_permissions_and_page_access(
self, role_id: str, domain_id: str
self, role_id: str, domain_id: str
) -> Tuple[List[str], List[str]]:
role_vo = self.role_mgr.get_role(role_id=role_id, domain_id=domain_id)
return role_vo.permissions, role_vo.page_access

def _get_user_projects_in_project_group(
self, domain_id: str, workspace_id: str, user_id: str
self, domain_id: str, workspace_id: str, user_id: str
) -> List[str]:
user_projects = []
project_groups = self.project_group_mgr.filter_project_groups(
Expand All @@ -384,7 +384,7 @@ def _get_user_projects_in_project_group(
return user_projects

def _get_user_projects(
self, user_id: str, workspace_id: str, domain_id: str
self, user_id: str, workspace_id: str, domain_id: str
) -> List[str]:
user_projects = []

Expand Down Expand Up @@ -419,7 +419,7 @@ def _check_user_required_actions(required_actions: list, user_id: str) -> None:
expire=600,
)
def _get_combined_role_permissions_and_page_access(
self, role_type: str, user_id: str, domain_id: str
self, role_type: str, user_id: str, domain_id: str
) -> Tuple[List[str], List[str]]:
role_bindings = self.rb_mgr.filter_role_bindings(
role_type=role_type,
Expand Down
Loading

0 comments on commit d03d245

Please sign in to comment.