Skip to content

Commit

Permalink
feat(collaboration): support for configuring database administrators …
Browse files Browse the repository at this point in the history
…and participating in approvals (#2168)

* feat(collaboration): support database resource role (#1782)

* feat(database-owner):
1. Add the owner role to the database, supporting approval workflow to use the owner role of the database.
2. Add variables for integrating external approval.
such as:
database.owner.accounts
database.owner.ids
database.owner.names
database.name
environment.name
task.description
risk.level

2024-02-29

* feat(database-owner):
1. Add the owner role to the database, supporting approval workflow to use the owner role of the database.
2. Add variables for integrating external approval.
such as:
database.owner.accounts
database.owner.ids
database.owner.names
database.name
environment.name
task.description
risk.level

2024-02-29

* feat(database-owner):
1. Add the owner role to the database, supporting approval workflow to use the owner role of the database.
2. Add variables for integrating external approval.
such as:
database.owner.accounts
database.owner.ids
database.owner.names
database.name
environment.name
task.description
risk.level

2024-02-29

* feat(database-owner):
1. Add the owner role to the database, supporting approval workflow to use the owner role of the database.
2. Add variables for integrating external approval.
such as:
database.owner.accounts
database.owner.ids
database.owner.names
database.name
environment.name
task.description
risk.level
odc.task.url
3. Adjust the database permission request form, and split the form when applying for multiple databases.

2024-03-06

* feat(database-owner):
1. Add the owner role to the database, supporting approval workflow to use the owner role of the database.
2. Add variables for integrating external approval.
such as:
database.owner.accounts
database.owner.ids
database.owner.names
database.name
environment.name
task.description
risk.level
odc.task.url
3. Adjust the database permission request form, and split the form when applying for multiple databases.

2024-03-06

* feat(database-owner):
1. Add the owner role to the database, supporting approval workflow to use the owner role of the database.
2. Add variables for integrating external approval.
such as:
database.owner.accounts
database.owner.ids
database.owner.names
database.name
environment.name
task.description
risk.level
odc.task.url
3. Adjust the database permission request form, and split the form when applying for multiple databases.

2024-03-07

* feat(database-owner):
1. Add the owner role to the database, supporting approval workflow to use the owner role of the database.
2. Add variables for integrating external approval.
such as:
database.owner.accounts
database.owner.ids
database.owner.names
database.name
environment.name
task.description
risk.level
odc.task.url
3. Adjust the database permission request form, and split the form when applying for multiple databases.

2024-03-08

* feat(database-owner):
1. Add the owner role to the database, supporting approval workflow to use the owner role of the database.
2. Add variables for integrating external approval.
such as:
database.owner.accounts
database.owner.ids
database.owner.names
database.name
environment.name
task.description
risk.level
odc.task.url
3. Adjust the database permission request form, and split the form when applying for multiple databases.

2024-03-08

* feat(database-owner):
1. Add the owner role to the database, supporting approval workflow to use the owner role of the database.
2. Add variables for integrating external approval.
such as:
database.owner.accounts
database.owner.ids
database.owner.names
database.name
environment.name
task.description
risk.level
odc.task.url
3. Adjust the database permission request form, and split the form when applying for multiple databases.

2024-03-08

* modify migrate script version number

* update submodule

* refine codes and fix some issues

* refine

* fix a bug

* response to CR

---------

Co-authored-by: isadba <chinafenghao@hotmail.com>
  • Loading branch information
smallsheeeep and ISADBA authored Apr 12, 2024
1 parent 485d78b commit cb13278
Show file tree
Hide file tree
Showing 24 changed files with 527 additions and 153 deletions.
2 changes: 1 addition & 1 deletion client
Submodule client updated 45 files
+16 −0 src/common/network/projectNotification.ts
+16 −0 src/component/Input/Case/index.tsx
+16 −0 src/component/Input/Keymap/index.tsx
+16 −0 src/component/Input/Keymap/keycodemap.ts
+16 −0 src/component/MonacoEditor/DiffEditor.tsx
+16 −0 src/component/MonacoEditor/config.ts
+16 −0 src/component/MonacoEditor/plugins/theme/github.ts
+16 −0 src/component/MonacoEditor/plugins/theme/index.ts
+16 −0 src/component/MonacoEditor/plugins/theme/monokai.ts
+16 −0 src/component/ODCSetting/Item/InputItem.tsx
+16 −0 src/component/ODCSetting/Item/RadioItem.tsx
+16 −0 src/component/ODCSetting/Item/SelectItem.tsx
+16 −0 src/component/ODCSetting/Item/TextItem.tsx
+16 −0 src/component/ODCSetting/config.tsx
+16 −0 src/component/ODCSetting/config/account.tsx
+16 −0 src/component/ODCSetting/config/database.tsx
+16 −0 src/component/ODCSetting/config/editor.tsx
+16 −0 src/component/ODCSetting/config/performance.tsx
+16 −0 src/component/ODCSetting/config/preference.tsx
+16 −0 src/component/ODCSetting/index.tsx
+16 −0 src/component/Task/StructureComparisonTask/CreateModal/TableSelector.tsx
+16 −0 src/component/Task/StructureComparisonTask/CreateModal/index.tsx
+16 −0 src/component/Task/StructureComparisonTask/CreateModal/interface.ts
+16 −0 src/component/Task/component/PartitionPolicyFormTable/EditTable/index.tsx
+16 −0 src/component/Task/component/PartitionPolicyFormTable/RuleFormItem/index.tsx
+16 −0 src/component/Task/component/PartitionPolicyFormTable/const.ts
+16 −0 src/component/Task/const.ts
+16 −0 src/component/Task/hooks/useProjects.tsx
+16 −0 src/d.ts/projectNotification.ts
+16 −0 src/d.ts/task.ts
+2 −0 src/page/Datasource/Info/NewDataBaseButton/index.tsx
+16 −0 src/page/Login/components/LDAPModal/index.tsx
+16 −0 src/page/Project/Database/StatusName.tsx
+16 −0 src/page/Project/Notification/components/Channel.tsx
+16 −0 src/page/Project/Notification/components/Message.tsx
+16 −0 src/page/Project/Notification/components/MessageStatus.tsx
+16 −0 src/page/Project/Notification/components/Policy.tsx
+16 −0 src/page/Project/Notification/components/columns.tsx
+16 −0 src/page/Project/Notification/components/interface.ts
+16 −0 src/page/Secure/Env/components/FormEnvironmentModal.tsx
+16 −0 src/page/Workspace/components/SessionContextWrap/SessionSelect/SelectItem.tsx
+16 −0 src/page/Workspace/components/SessionContextWrap/SessionSelect/const.ts
+16 −0 src/util/broadcastChannel.ts
+16 −0 src/util/sentry.ts
+16 −0 src/util/versionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ public void testCreateProject_Success() {
@Test
public void testGetProject_Success() {
Project saved = projectService.create(getProject());
Mockito.when(resourceRoleService.listByResourceId(Mockito.any()))
Mockito.when(
resourceRoleService.listByResourceTypeAndId(Mockito.eq(ResourceType.ODC_PROJECT), Mockito.anyLong()))
.thenReturn(listUserResourceRole(saved.getId()));
Project actual = projectService.detail(saved.getId());
Assert.assertNotNull(actual);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,13 @@ public void testFindById_Success() {
public void testTransfer_Success() {
Mockito.when(connectionService.checkPermission(Mockito.anyList(), Mockito.anyList())).thenReturn(true);
Mockito.when(projectPermissionValidator.hasProjectRole(Mockito.anyList(), Mockito.anyList())).thenReturn(true);
databaseRepository.saveAndFlush(getEntity());
DatabaseEntity saved = databaseRepository.saveAndFlush(getEntity());
TransferDatabasesReq req = new TransferDatabasesReq();
req.setDatabaseIds(Arrays.asList(1L));
req.setDatabaseIds(Arrays.asList(saved.getId()));
req.setProjectId(2L);
Assert.assertTrue(databaseService.transfer(req));
Assert.assertEquals(2L, databaseRepository.findById(1L).get().getProjectId().longValue());
Assert.assertEquals(2L, databaseRepository.findById(saved.getId()).get().getProjectId().longValue());

}

private DatabaseEntity getEntity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ public void testSaveAll_Success() {
Mockito.when(resourceRoleRepository.findAll()).thenReturn(getResourceRoleEntity());
Mockito.when(resourceRoleRepository.findById(1L)).thenReturn(Optional.of(getResourceRoleEntity().get(0)));
Mockito.when(authenticationFacade.currentOrganizationId()).thenReturn(1L);

resourceRoleService.saveAll(Arrays.asList(getProjectOwner()));

int actual = userResourceRoleRepository.findByUserId(1L).size();
Assert.assertEquals(1, actual);
}
Expand All @@ -83,8 +81,7 @@ public void testListByResourceId_Success() {
.thenReturn(Optional.of(getResourceRoleEntity().get(0)));
Mockito.when(authenticationFacade.currentOrganizationId()).thenReturn(1L);
resourceRoleService.saveAll(Arrays.asList(getProjectOwner()));

int actual = resourceRoleService.listByResourceId(1L).size();
int actual = resourceRoleService.listByResourceTypeAndId(ResourceType.ODC_PROJECT, 1L).size();
Assert.assertEquals(1, actual);
}

Expand All @@ -94,7 +91,6 @@ public void testListByOrganizationIdAndUserId_Success() {
Mockito.when(resourceRoleRepository.findById(1L)).thenReturn(Optional.of(getResourceRoleEntity().get(0)));
Mockito.when(authenticationFacade.currentOrganizationId()).thenReturn(1L);
resourceRoleService.saveAll(Arrays.asList(getProjectOwner()));

int actual = resourceRoleService.listByOrganizationIdAndUserId(1L, 1L).size();
Assert.assertEquals(1, actual);
}
Expand All @@ -105,15 +101,15 @@ public void testDeleteById_Success() {
Mockito.when(resourceRoleRepository.findById(1L)).thenReturn(Optional.of(getResourceRoleEntity().get(0)));
Mockito.when(authenticationFacade.currentOrganizationId()).thenReturn(1L);
resourceRoleService.saveAll(Arrays.asList(getProjectOwner()));

int actual = resourceRoleService.deleteByResourceId(1L);
int actual = userResourceRoleRepository.deleteByResourceId(1L);
Assert.assertEquals(1, actual);
}

private UserResourceRole getProjectOwner() {
UserResourceRole projectOwner = new UserResourceRole();
projectOwner.setUserId(1L);
projectOwner.setResourceId(1L);
projectOwner.setResourceType(ResourceType.ODC_PROJECT);
projectOwner.setResourceRole(ResourceRoleName.OWNER);
return projectOwner;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,4 +431,14 @@ public static boolean startsWithIgnoreSpaceAndNewLines(@NonNull String target, @
return matchLength >= maxMatchLength || j >= prefixes.length;
}

public static boolean isTranslatable(@NonNull String str) {
return str.startsWith(DEFAULT_VARIABLE_PREFIX) && str.endsWith(DEFAULT_VARIABLE_SUFFIX);
}

public static String getTranslatableKey(@NonNull String str) {
if (!isTranslatable(str)) {
throw new IllegalStateException(str + " is not translatable");
}
return str.substring(DEFAULT_VARIABLE_PREFIX.length(), str.length() - DEFAULT_VARIABLE_SUFFIX.length());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
kind: resource
version: v2
templates:
- metadata:
allow_duplicate: false
table_name: iam_resource_role
unique_keys: [ "resource_type", "role_name" ]
specs:
- column_name: id
default_value: 6
data_type: java.lang.Long
- column_name: resource_type
value: "ODC_DATABASE"
- column_name: role_name
value: "OWNER"
- column_name: description
value: "built-in resource role, database owner"
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.oceanbase.odc.service.connection.database.model.CreateDatabaseReq;
import com.oceanbase.odc.service.connection.database.model.Database;
import com.oceanbase.odc.service.connection.database.model.DeleteDatabasesReq;
import com.oceanbase.odc.service.connection.database.model.ModifyDatabaseOwnerReq;
import com.oceanbase.odc.service.connection.database.model.QueryDatabaseParams;
import com.oceanbase.odc.service.connection.database.model.TransferDatabasesReq;

Expand Down Expand Up @@ -103,4 +104,11 @@ public SuccessResponse<Boolean> transferDatabase(@RequestBody TransferDatabasesR
public SuccessResponse<Boolean> deleteDatabases(@RequestBody DeleteDatabasesReq req) {
return Responses.success(databaseService.deleteDatabases(req));
}

@ApiOperation(value = "modifyDatabasesOwner", notes = "modify database owner")
@RequestMapping(value = "/databases/owner/{projectId:[\\d]+}", method = RequestMethod.PUT)
public SuccessResponse<Boolean> modifyDatabasesOwners(@PathVariable Long projectId,
@RequestBody ModifyDatabaseOwnerReq req) {
return Responses.success(databaseService.modifyDatabasesOwners(projectId, req));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

import com.oceanbase.odc.common.json.JsonUtils;
import com.oceanbase.odc.core.shared.constant.ErrorCodes;
import com.oceanbase.odc.core.shared.constant.ResourceType;
import com.oceanbase.odc.core.shared.exception.BadRequestException;
import com.oceanbase.odc.service.captcha.CaptchaService;
import com.oceanbase.odc.service.captcha.VerificationCode;
Expand Down Expand Up @@ -331,8 +332,10 @@ public PaginatedResponse<Role> listRoles(

@ApiOperation(value = "listResourceRoles", notes = "list resource roles")
@RequestMapping(value = "/resourceRoles", method = RequestMethod.GET)
public ListResponse<ResourceRole> listResourceRoles() {
return Responses.list(resourceRoleService.listResourceRoles());
public ListResponse<ResourceRole> listResourceRoles(
@RequestParam(required = false, value = "resourceType",
defaultValue = "ODC_PROJECT") List<ResourceType> resourceType) {
return Responses.list(resourceRoleService.listResourceRoles(resourceType));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import com.oceanbase.odc.metadb.collaboration.ProjectEntity;
import com.oceanbase.odc.metadb.collaboration.ProjectRepository;
import com.oceanbase.odc.service.collaboration.environment.EnvironmentService;
import com.oceanbase.odc.service.collaboration.project.ProjectService;
import com.oceanbase.odc.service.config.UserConfigService;
import com.oceanbase.odc.service.connection.ConnectionService;
import com.oceanbase.odc.service.connection.model.ConnectionConfig;
Expand Down Expand Up @@ -71,9 +70,6 @@ public class HookConfiguration {
@Autowired
private RiskLevelService riskLevelService;

@Autowired
private ProjectService projectService;

@Autowired
private ResourceRoleService resourceRoleService;

Expand All @@ -96,7 +92,7 @@ public class HookConfiguration {
public void init() {
userService.addPostUserDeleteHook(event -> {
Long userId = event.getUserId();
projectService.deleteUserRelatedProjectRoles(userId);
resourceRoleService.deleteByUserId(userId);
userConfigService.deleteUserConfigurations(userId);
});
log.info("PostUserDeleteHook added");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ public interface ResourceRoleRepository

List<ResourceRoleEntity> findByResourceType(ResourceType resourceType);

List<ResourceRoleEntity> findByResourceTypeIn(List<ResourceType> resourceType);

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,50 +18,110 @@
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Function;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

public interface UserResourceRoleRepository
extends JpaRepository<UserResourceRoleEntity, Long>, JpaSpecificationExecutor<UserResourceRoleEntity> {
List<UserResourceRoleEntity> findByOrganizationIdAndUserId(Long organizationId, Long userId);
import com.oceanbase.odc.common.jpa.InsertSqlTemplateBuilder;
import com.oceanbase.odc.config.jpa.OdcJpaRepository;
import com.oceanbase.odc.core.shared.constant.ResourceType;

public interface UserResourceRoleRepository extends OdcJpaRepository<UserResourceRoleEntity, Long> {

List<UserResourceRoleEntity> findByOrganizationIdAndUserId(Long organizationId, Long userId);

List<UserResourceRoleEntity> findByUserId(Long userId);

List<UserResourceRoleEntity> findByResourceId(Long resourceId);

List<UserResourceRoleEntity> findByResourceIdIn(Collection<Long> resourceIds);

@Modifying
@Transactional
@Query(value = "delete from iam_user_resource_role t where t.user_id =:userId", nativeQuery = true)
int deleteByUserId(@Param("userId") Long userId);

@Query(nativeQuery = true,
value = "select t.* from iam_user_resource_role t where concat(t.resource_id, ':', t.resource_role_id) in (:resourceRoleIdentifiers)")
List<UserResourceRoleEntity> findByResourceIdsAndResourceRoleIdsIn(
@Param("resourceRoleIdentifiers") Set<String> resourceRoleIdentifiers);


@Modifying
@Transactional
@Query(value = "delete from iam_user_resource_role t where t.resource_id =:resourceId", nativeQuery = true)
int deleteByResourceId(@Param("resourceId") Long resourceId);

@Modifying
@Transactional
@Query(value = "delete from iam_user_resource_role t where t.resource_id =:resourceId and t.user_id =:userId",
@Query(value = "delete from iam_user_resource_role i_urr where i_urr.resource_id = :resourceId and i_urr.resource_role_id "
+ "in (select i_rr.id from iam_resource_role i_rr where i_rr.resource_type = :#{#resourceType.name()})",
nativeQuery = true)
int deleteByResourceTypeAndId(@Param("resourceType") ResourceType resourceType,
@Param("resourceId") Long resourceId);

@Modifying
@Transactional
@Query(value = "delete from iam_user_resource_role i_urr where i_urr.resource_id in (:resourceIds) and i_urr.resource_role_id "
+ "in (select i_rr.id from iam_resource_role i_rr where i_rr.resource_type = :#{#resourceType.name()})",
nativeQuery = true)
int deleteByResourceIdAndUserId(@Param("resourceId") Long resourceId, @Param("userId") Long userId);
int deleteByResourceTypeAndIdIn(@Param("resourceType") ResourceType resourceType,
@Param("resourceIds") Collection<Long> resourceIds);

@Modifying
@Transactional
@Query(value = "delete from iam_user_resource_role t where t.resource_id in (:resourceIds) and t.user_id =:userId",
@Query(value = "delete from iam_user_resource_role i_urr where i_urr.user_id = :userId and i_urr.resource_id = :resourceId "
+ "and i_urr.resource_role_id in (select i_rr.id from iam_resource_role i_rr where i_rr.resource_type = :#{#resourceType.name()})",
nativeQuery = true)
int deleteByUserIdAndResourceIdIn(@Param("userId") Long userId, @Param("resourceIds") Set<Long> resourceIds);
int deleteByUserIdAndResourceIdAndResourceType(@Param("userId") Long userId, @Param("resourceId") Long resourceId,
@Param("resourceType") ResourceType resourceType);

@Modifying
@Transactional
@Query(value = "delete from iam_user_resource_role i_urr where i_urr.user_id = :userId and i_urr.resource_id in (:resourceIds) "
+ "and i_urr.resource_role_id in (select i_rr.id from iam_resource_role i_rr where i_rr.resource_type = :#{#resourceType.name()})",
nativeQuery = true)
int deleteByUserIdAndResourceIdInAndResourceType(@Param("userId") Long userId,
@Param("resourceIds") Collection<Long> resourceIds, @Param("resourceType") ResourceType resourceType);

@Query(nativeQuery = true,
value = "select t.* from iam_user_resource_role t where concat(t.resource_id, ':', t.resource_role_id) in (:resourceRoleIdentifiers)")
List<UserResourceRoleEntity> findByResourceIdsAndResourceRoleIdsIn(
@Param("resourceRoleIdentifiers") Set<String> resourceRoleIdentifiers);

@Query(value = "select i_urr.* from iam_user_resource_role i_urr inner join iam_resource_role i_rr on "
+ "i_urr.resource_role_id = i_rr.id where i_rr.resource_type = :#{#resourceType.name()} and i_urr.resource_id = :resourceId",
nativeQuery = true)
List<UserResourceRoleEntity> listByResourceTypeAndId(
@Param("resourceType") ResourceType resourceType, @Param("resourceId") Long resourceId);

@Query(value = "select i_urr.* from iam_user_resource_role i_urr inner join iam_resource_role i_rr on "
+ "i_urr.resource_role_id = i_rr.id where i_rr.resource_type = :#{#resourceType.name()} and i_urr.resource_id in (:resourceIds)",
nativeQuery = true)
List<UserResourceRoleEntity> listByResourceTypeAndIdIn(
@Param("resourceType") ResourceType resourceType, @Param("resourceIds") Collection<Long> resourceIds);

@Query(value = "select i_urr.* from iam_user_resource_role i_urr inner join iam_resource_role i_rr on i_urr.resource_role_id = i_rr.id "
+ "where i_rr.resource_type = :#{#resourceType.name()} and i_rr.role_name = :roleName and i_urr.resource_id = :resourceId",
nativeQuery = true)
List<UserResourceRoleEntity> findByResourceIdAndTypeAndName(@Param("resourceId") Long resourceId,
@Param("resourceType") ResourceType resourceType, @Param("roleName") String roleName);

@Query(value = "select i_urr.* from iam_user_resource_role i_urr inner join iam_resource_role i_rr on i_urr.resource_role_id = i_rr.id "
+ "where i_rr.resource_type = :#{#resourceType.name()} and i_urr.user_id = :userId",
nativeQuery = true)
List<UserResourceRoleEntity> findByUserIdAndResourceType(@Param("userId") Long userId,
@Param("resourceType") ResourceType resourceType);

default List<UserResourceRoleEntity> batchCreate(List<UserResourceRoleEntity> entities) {
String sql = InsertSqlTemplateBuilder.from("iam_user_resource_role")
.field(UserResourceRoleEntity_.userId)
.field(UserResourceRoleEntity_.resourceId)
.field(UserResourceRoleEntity_.resourceRoleId)
.field(UserResourceRoleEntity_.organizationId)
.build();
List<Function<UserResourceRoleEntity, Object>> getter = valueGetterBuilder()
.add(UserResourceRoleEntity::getUserId)
.add(UserResourceRoleEntity::getResourceId)
.add(UserResourceRoleEntity::getResourceRoleId)
.add(UserResourceRoleEntity::getOrganizationId)
.build();
return batchCreate(entities, sql, getter, UserResourceRoleEntity::setId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.oceanbase.odc.service.automation;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -29,6 +30,7 @@

import com.oceanbase.odc.common.lang.Pair;
import com.oceanbase.odc.core.authority.util.SkipAuthorize;
import com.oceanbase.odc.core.shared.constant.ResourceType;
import com.oceanbase.odc.service.automation.model.AutomationAction;
import com.oceanbase.odc.service.automation.model.AutomationCondition;
import com.oceanbase.odc.service.automation.model.AutomationRule;
Expand Down Expand Up @@ -127,15 +129,16 @@ protected void bindPermission(Long userId, AutomationAction action) {
protected void bindProjectRole(Long userId, AutomationAction action) {
Long projectId = ((Integer) action.getArguments().get("projectId")).longValue();
List<Integer> roleIds = (List<Integer>) action.getArguments().get("roles");
List<ProjectMember> members = resourceRoleService.listResourceRoles().stream()
.filter(resourceRole -> roleIds.contains(resourceRole.getId().intValue()))
.map(resourceRole -> {
ProjectMember member = new ProjectMember();
member.setRole(resourceRole.getRoleName());
member.setId(userId);
return member;
})
.collect(Collectors.toList());
List<ProjectMember> members =
resourceRoleService.listResourceRoles(Collections.singletonList(ResourceType.ODC_PROJECT)).stream()
.filter(resourceRole -> roleIds.contains(resourceRole.getId().intValue()))
.map(resourceRole -> {
ProjectMember member = new ProjectMember();
member.setRole(resourceRole.getRoleName());
member.setId(userId);
return member;
})
.collect(Collectors.toList());
projectService.createMembersSkipPermissionCheck(projectId, action.getOrganizationId(), members);
}

Expand Down
Loading

0 comments on commit cb13278

Please sign in to comment.