You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by zi...@apache.org on 2022/10/27 10:02:00 UTC
[dolphinscheduler] branch dev updated: [Feature-12040][api][ui] Add authorization management of read and write permissions for project center (#12048)
This is an automated email from the ASF dual-hosted git repository.
zixi0825 pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git
The following commit(s) were added to refs/heads/dev by this push:
new dc8d18cf87 [Feature-12040][api][ui] Add authorization management of read and write permissions for project center (#12048)
dc8d18cf87 is described below
commit dc8d18cf871c9c54f2a7e10023469428bc19f983
Author: Yiming Guo <49...@users.noreply.github.com>
AuthorDate: Thu Oct 27 18:01:51 2022 +0800
[Feature-12040][api][ui] Add authorization management of read and write permissions for project center (#12048)
[Feature-12040][api][ui] Add authorization management of read and write permissions for project center
---
.../api/controller/ProjectController.java | 57 ++++++++
.../api/controller/UsersController.java | 48 +++++++
.../apache/dolphinscheduler/api/enums/Status.java | 2 +
.../ResourcePermissionCheckServiceImpl.java | 2 +-
.../api/service/ProjectService.java | 24 ++++
.../api/service/ResourcesService.java | 4 +-
.../dolphinscheduler/api/service/UsersService.java | 19 +++
.../service/impl/ProcessDefinitionServiceImpl.java | 28 ++--
.../api/service/impl/ProjectServiceImpl.java | 156 ++++++++++++++++++++-
.../service/impl/TaskDefinitionServiceImpl.java | 33 +++--
.../api/service/impl/UsersServiceImpl.java | 97 ++++++++++++-
.../api/service/ProcessDefinitionServiceTest.java | 1 +
.../api/service/ProjectServiceTest.java | 106 +++++++++++++-
.../api/service/TaskDefinitionServiceImplTest.java | 8 +-
.../api/service/UsersServiceTest.java | 46 ++++++
.../dao/mapper/ProjectUserMapper.java | 2 +-
.../src/common/column-width-config.ts | 3 +
dolphinscheduler-ui/src/locales/en_US/project.ts | 6 +-
dolphinscheduler-ui/src/locales/en_US/security.ts | 3 +
dolphinscheduler-ui/src/locales/zh_CN/project.ts | 6 +-
dolphinscheduler-ui/src/locales/zh_CN/security.ts | 3 +
.../src/service/modules/projects/index.ts | 18 ++-
.../src/service/modules/projects/types.ts | 8 ++
.../src/service/modules/users/index.ts | 16 +++
.../user-manage/components/authorize-modal.tsx | 94 +++++++++++--
.../user-manage/components/use-authorize.ts | 91 ++++++++----
.../security/user-manage/components/use-columns.ts | 91 ++++++++++++
.../views/security/user-manage/index.module.scss | 5 +
28 files changed, 899 insertions(+), 78 deletions(-)
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectController.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectController.java
index 1b3f2def46..dcfc774b4c 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectController.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectController.java
@@ -174,6 +174,43 @@ public class ProjectController extends BaseController {
return result;
}
+ /**
+ * query project with authorized level list paging
+ *
+ * @param userId user id
+ * @param loginUser login user
+ * @param searchVal search value
+ * @param pageSize page size
+ * @param pageNo page number
+ * @return project list which with the login user's authorized level
+ */
+ @Operation(summary = "queryProjectWithAuthorizedLevelListPaging", description = "QUERY_PROJECT_WITH_AUTH_LEVEL_LIST_PAGING_NOTES")
+ @Parameters({
+ @Parameter(name = "userId", description = "USER_ID", schema = @Schema(implementation = int.class, example = "100")),
+ @Parameter(name = "searchVal", description = "SEARCH_VAL", schema = @Schema(implementation = String.class)),
+ @Parameter(name = "pageSize", description = "PAGE_SIZE", required = true, schema = @Schema(implementation = int.class, example = "10")),
+ @Parameter(name = "pageNo", description = "PAGE_NO", required = true, schema = @Schema(implementation = int.class, example = "1"))
+ })
+ @GetMapping(value = "/project-with-authorized-level-list-paging")
+ @ResponseStatus(HttpStatus.OK)
+ @ApiException(LOGIN_USER_QUERY_PROJECT_LIST_PAGING_ERROR)
+ @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
+ public Result queryProjectWithAuthorizedLevelListPaging(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
+ @RequestParam("userId") Integer userId,
+ @RequestParam(value = "searchVal", required = false) String searchVal,
+ @RequestParam("pageSize") Integer pageSize,
+ @RequestParam("pageNo") Integer pageNo) {
+
+ Result result = checkPageParams(pageNo, pageSize);
+ if (!result.checkResult()) {
+ return result;
+ }
+ searchVal = ParameterUtils.handleEscapes(searchVal);
+ result = projectService.queryProjectWithAuthorizedLevelListPaging(userId, loginUser, pageSize, pageNo,
+ searchVal);
+ return result;
+ }
+
/**
* delete project by code
*
@@ -234,6 +271,26 @@ public class ProjectController extends BaseController {
return projectService.queryAuthorizedProject(loginUser, userId);
}
+ /**
+ * query all project with authorized level
+ *
+ * @param loginUser login user
+ * @param userId user id
+ * @return All projects with users' authorized level for them
+ */
+ @Operation(summary = "queryProjectWithAuthorizedLevel", description = "QUERY_PROJECT_AUTHORIZED_LEVEL")
+ @Parameters({
+ @Parameter(name = "userId", description = "USER_ID", schema = @Schema(implementation = int.class, example = "100"))
+ })
+ @GetMapping(value = "/project-with-authorized-level")
+ @ResponseStatus(HttpStatus.OK)
+ @ApiException(QUERY_AUTHORIZED_PROJECT)
+ @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
+ public Result queryProjectWithAuthorizedLevel(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
+ @RequestParam("userId") Integer userId) {
+ return projectService.queryProjectWithAuthorizedLevel(loginUser, userId);
+ }
+
/**
* query authorized user
*
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UsersController.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UsersController.java
index dcaf7a9b81..93c13b6f50 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UsersController.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UsersController.java
@@ -214,6 +214,54 @@ public class UsersController extends BaseController {
return returnDataList(result);
}
+ /**
+ * revoke project By Id
+ *
+ * @param loginUser login user
+ * @param userId user id
+ * @param projectIds project id array
+ * @return revoke result code
+ */
+ @Operation(summary = "revokeProjectById", description = "REVOKE_PROJECT_NOTES")
+ @Parameters({
+ @Parameter(name = "userId", description = "USER_ID", required = true, schema = @Schema(implementation = int.class, example = "100")),
+ @Parameter(name = "projectIds", description = "PROJECT_IDS", required = true, schema = @Schema(implementation = String.class))
+ })
+ @PostMapping(value = "/revoke-project-by-id")
+ @ResponseStatus(HttpStatus.OK)
+ @ApiException(REVOKE_PROJECT_ERROR)
+ @AccessLogAnnotation
+ public Result revokeProjectById(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
+ @RequestParam(value = "userId") int userId,
+ @RequestParam(value = "projectIds") String projectIds) {
+ Map<String, Object> result = usersService.revokeProjectById(loginUser, userId, projectIds);
+ return returnDataList(result);
+ }
+
+ /**
+ * grant project with read permission
+ *
+ * @param loginUser login user
+ * @param userId user id
+ * @param projectIds project id array
+ * @return grant result code
+ */
+ @Operation(summary = "grantProjectWithReadPerm", description = "GRANT_PROJECT_WITH_READ_PERM_NOTES")
+ @Parameters({
+ @Parameter(name = "userId", description = "USER_ID", required = true, schema = @Schema(implementation = int.class, example = "100")),
+ @Parameter(name = "projectIds", description = "PROJECT_IDS", required = true, schema = @Schema(implementation = String.class))
+ })
+ @PostMapping(value = "/grant-project-with-read-perm")
+ @ResponseStatus(HttpStatus.OK)
+ @ApiException(GRANT_PROJECT_ERROR)
+ @AccessLogAnnotation
+ public Result grantProjectWithReadPerm(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
+ @RequestParam(value = "userId") int userId,
+ @RequestParam(value = "projectIds") String projectIds) {
+ Map<String, Object> result = usersService.grantProjectWithReadPerm(loginUser, userId, projectIds);
+ return returnDataList(result);
+ }
+
/**
* grant project
*
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
index 2c67861426..f6d8257ec9 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
@@ -280,6 +280,8 @@ public enum Status {
USER_NO_OPERATION_PERM(30001, "user has no operation privilege", "当前用户没有操作权限"),
USER_NO_OPERATION_PROJECT_PERM(30002, "user {0} is not has project {1} permission", "当前用户[{0}]没有[{1}]项目的操作权限"),
+ USER_NO_WRITE_PROJECT_PERM(30003, "user [{0}] does not have write permission for project [{1}]",
+ "当前用户[{0}]没有[{1}]项目的写权限"),
PROCESS_INSTANCE_NOT_EXIST(50001, "process instance {0} does not exist", "工作流实例[{0}]不存在"),
PROCESS_INSTANCE_EXIST(50002, "process instance {0} already exists", "工作流实例[{0}]已存在"),
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/permission/ResourcePermissionCheckServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/permission/ResourcePermissionCheckServiceImpl.java
index 7b3da83bf5..bf3d48e4cf 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/permission/ResourcePermissionCheckServiceImpl.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/permission/ResourcePermissionCheckServiceImpl.java
@@ -242,7 +242,7 @@ public class ResourcePermissionCheckServiceImpl
}
List<Resource> ownResourceList = resourceMapper.queryResourceListAuthored(userId, -1);
relationResources.addAll(ownResourceList);
- return ownResourceList.stream().map(Resource::getId).collect(toSet());
+ return relationResources.stream().map(Resource::getId).collect(toSet());
}
@Override
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProjectService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProjectService.java
index a0d7217766..43b8a04acf 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProjectService.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProjectService.java
@@ -81,6 +81,10 @@ public interface ProjectService {
*/
boolean hasProjectAndPerm(User loginUser, Project project, Result result, String permission);
+ boolean hasProjectAndWritePerm(User loginUser, Project project, Result result);
+
+ boolean hasProjectAndWritePerm(User loginUser, Project project, Map<String, Object> result);
+
/**
* admin can view all projects
*
@@ -92,6 +96,19 @@ public interface ProjectService {
*/
Result queryProjectListPaging(User loginUser, Integer pageSize, Integer pageNo, String searchVal);
+ /**
+ * admin can view all projects
+ *
+ * @param userId user id
+ * @param loginUser login user
+ * @param searchVal search value
+ * @param pageSize page size
+ * @param pageNo page number
+ * @return project list which with the login user's authorized level
+ */
+ Result queryProjectWithAuthorizedLevelListPaging(Integer userId, User loginUser, Integer pageSize, Integer pageNo,
+ String searchVal);
+
/**
* delete project by code
*
@@ -131,6 +148,13 @@ public interface ProjectService {
*/
Result queryAuthorizedProject(User loginUser, Integer userId);
+ /**
+ * query all project with authorized level
+ * @param loginUser login user
+ * @return project list
+ */
+ Result queryProjectWithAuthorizedLevel(User loginUser, Integer userId);
+
/**
* query authorized user
*
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ResourcesService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ResourcesService.java
index 04f477e36b..c0c7a7d211 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ResourcesService.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ResourcesService.java
@@ -195,7 +195,9 @@ public interface ResourcesService {
/**
* updateProcessInstance resource
*
- * @param resourceId resource id
+ * @param loginUser login user
+ * @param fullName full name
+ * @param tenantCode tenantCode
* @param content content
* @return update result cod
*/
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java
index d854e9afdd..9abe60c72c 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java
@@ -153,6 +153,16 @@ public interface UsersService {
*/
Map<String, Object> grantProject(User loginUser, int userId, String projectIds);
+ /**
+ * grant project with read permission
+ *
+ * @param loginUser login user
+ * @param userId user id
+ * @param projectIds project id array
+ * @return grant result code
+ */
+ Map<String, Object> grantProjectWithReadPerm(User loginUser, int userId, String projectIds);
+
/**
* grant project by code
*
@@ -163,6 +173,15 @@ public interface UsersService {
*/
Map<String, Object> grantProjectByCode(User loginUser, int userId, long projectCode);
+ /**
+ * revoke the project permission for specified user by id
+ * @param loginUser Login user
+ * @param userId User id
+ * @param projectIds project id array
+ * @return
+ */
+ Map<String, Object> revokeProjectById(User loginUser, int userId, String projectIds);
+
/**
* revoke the project permission for specified user.
* @param loginUser Login user
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
index acb05b897e..fc01482236 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
@@ -261,10 +261,12 @@ public class ProcessDefinitionServiceImpl extends BaseServiceImpl implements Pro
String otherParamsJson,
ProcessExecutionTypeEnum executionType) {
Project project = projectMapper.queryByCode(projectCode);
- // check user access for project
+
+ // check if user have write perm for project
Map<String, Object> result =
projectService.checkProjectAndAuth(loginUser, project, projectCode, WORKFLOW_CREATE);
- if (result.get(Constants.STATUS) != Status.SUCCESS) {
+ boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
return result;
}
if (checkDescriptionLength(description)) {
@@ -754,12 +756,14 @@ public class ProcessDefinitionServiceImpl extends BaseServiceImpl implements Pro
String otherParamsJson,
ProcessExecutionTypeEnum executionType) {
Project project = projectMapper.queryByCode(projectCode);
- // check user access for project
+ // check if user have write perm for project
Map<String, Object> result =
projectService.checkProjectAndAuth(loginUser, project, projectCode, WORKFLOW_UPDATE);
- if (result.get(Constants.STATUS) != Status.SUCCESS) {
+ boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
return result;
}
+
if (checkDescriptionLength(description)) {
logger.warn("Parameter description is too long.");
putMsg(result, Status.DESCRIPTION_TOO_LONG_ERROR);
@@ -2404,12 +2408,14 @@ public class ProcessDefinitionServiceImpl extends BaseServiceImpl implements Pro
public Map<String, Object> deleteProcessDefinitionVersion(User loginUser, long projectCode, long code,
int version) {
Project project = projectMapper.queryByCode(projectCode);
- // check user access for project
+ // check if user have write perm for project
Map<String, Object> result =
projectService.checkProjectAndAuth(loginUser, project, projectCode, VERSION_DELETE);
- if (result.get(Constants.STATUS) != Status.SUCCESS) {
+ boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
return result;
}
+
ProcessDefinition processDefinition = processDefinitionMapper.queryByCode(code);
if (processDefinition == null || projectCode != processDefinition.getProjectCode()) {
@@ -2466,10 +2472,11 @@ public class ProcessDefinitionServiceImpl extends BaseServiceImpl implements Pro
String scheduleJson,
ProcessExecutionTypeEnum executionType) {
Project project = projectMapper.queryByCode(projectCode);
- // check user access for project
+ // check if user have write perm for project
Map<String, Object> result =
projectService.checkProjectAndAuth(loginUser, project, projectCode, WORKFLOW_CREATE);
- if (result.get(Constants.STATUS) != Status.SUCCESS) {
+ boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
return result;
}
if (checkDescriptionLength(description)) {
@@ -2613,10 +2620,11 @@ public class ProcessDefinitionServiceImpl extends BaseServiceImpl implements Pro
String otherParamsJson,
ProcessExecutionTypeEnum executionType) {
Project project = projectMapper.queryByCode(projectCode);
- // check user access for project
+ // check if user have write perm for project
Map<String, Object> result =
projectService.checkProjectAndAuth(loginUser, project, projectCode, WORKFLOW_UPDATE);
- if (result.get(Constants.STATUS) != Status.SUCCESS) {
+ boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
return result;
}
if (checkDescriptionLength(description)) {
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectServiceImpl.java
index 0ba236dd44..1353a30fed 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectServiceImpl.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectServiceImpl.java
@@ -20,7 +20,6 @@ package org.apache.dolphinscheduler.api.service.impl;
import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.PROJECT;
import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.PROJECT_CREATE;
import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.PROJECT_DELETE;
-import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.PROJECT_UPDATE;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.exceptions.ServiceException;
@@ -256,6 +255,60 @@ public class ProjectServiceImpl extends BaseServiceImpl implements ProjectServic
return checkResult;
}
+ @Override
+ public boolean hasProjectAndWritePerm(User loginUser, Project project, Result result) {
+ boolean checkResult = false;
+ if (project == null) {
+ logger.error("Project does not exist.");
+ putMsg(result, Status.PROJECT_NOT_FOUND, "");
+ } else {
+ // case 1: user is admin
+ if (loginUser.getUserType() == UserType.ADMIN_USER) {
+ return true;
+ }
+ // case 2: user is project owner
+ if (project.getUserId().equals(loginUser.getId())) {
+ return true;
+ }
+ // case 3: check user permission level
+ ProjectUser projectUser = projectUserMapper.queryProjectRelation(project.getId(), loginUser.getId());
+ if (projectUser == null || projectUser.getPerm() != Constants.DEFAULT_ADMIN_PERMISSION) {
+ putMsg(result, Status.USER_NO_WRITE_PROJECT_PERM, loginUser.getUserName(), project.getCode());
+ checkResult = false;
+ } else {
+ checkResult = true;
+ }
+ }
+ return checkResult;
+ }
+
+ @Override
+ public boolean hasProjectAndWritePerm(User loginUser, Project project, Map<String, Object> result) {
+ boolean checkResult = false;
+ if (project == null) {
+ logger.error("Project does not exist.");
+ putMsg(result, Status.PROJECT_NOT_FOUND, "");
+ } else {
+ // case 1: user is admin
+ if (loginUser.getUserType() == UserType.ADMIN_USER) {
+ return true;
+ }
+ // case 2: user is project owner
+ if (project.getUserId().equals(loginUser.getId())) {
+ return true;
+ }
+ // case 3: check user permission level
+ ProjectUser projectUser = projectUserMapper.queryProjectRelation(project.getId(), loginUser.getId());
+ if (projectUser == null || projectUser.getPerm() != Constants.DEFAULT_ADMIN_PERMISSION) {
+ putMsg(result, Status.USER_NO_WRITE_PROJECT_PERM, loginUser.getUserName(), project.getCode());
+ checkResult = false;
+ } else {
+ checkResult = true;
+ }
+ }
+ return checkResult;
+ }
+
@Override
public boolean hasProjectAndPerm(User loginUser, Project project, Result result, String permission) {
boolean checkResult = false;
@@ -310,6 +363,57 @@ public class ProjectServiceImpl extends BaseServiceImpl implements ProjectServic
return result;
}
+ /**
+ * admin can view all projects
+ *
+ * @param userId user id
+ * @param loginUser login user
+ * @param searchVal search value
+ * @param pageSize page size
+ * @param pageNo page number
+ * @return project list which with the login user's authorized level
+ */
+ @Override
+ public Result queryProjectWithAuthorizedLevelListPaging(Integer userId, User loginUser, Integer pageSize,
+ Integer pageNo, String searchVal) {
+ Result result = new Result();
+ PageInfo<Project> pageInfo = new PageInfo<>(pageNo, pageSize);
+ Page<Project> page = new Page<>(pageNo, pageSize);
+ Set<Integer> allProjectIds = resourcePermissionCheckService
+ .userOwnedResourceIdsAcquisition(AuthorizationType.PROJECTS, loginUser.getId(), logger);
+ Set<Integer> userProjectIds = resourcePermissionCheckService
+ .userOwnedResourceIdsAcquisition(AuthorizationType.PROJECTS, userId, logger);
+ if (allProjectIds.isEmpty()) {
+ result.setData(pageInfo);
+ putMsg(result, Status.SUCCESS);
+ return result;
+ }
+ IPage<Project> projectIPage =
+ projectMapper.queryProjectListPaging(page, new ArrayList<>(allProjectIds), searchVal);
+
+ List<Project> projectList = projectIPage.getRecords();
+
+ for (Project project : projectList) {
+ if (userProjectIds.contains(project.getId())) {
+ ProjectUser projectUser = projectUserMapper.queryProjectRelation(project.getId(), userId);
+ if (projectUser == null) {
+ // in this case, the user is the project owner, maybe it's better to set it to ALL_PERMISSION.
+ project.setPerm(Constants.DEFAULT_ADMIN_PERMISSION);
+ } else {
+ project.setPerm(projectUser.getPerm());
+ }
+ } else {
+ project.setPerm(0);
+ }
+ }
+
+ pageInfo.setTotal((int) projectIPage.getTotal());
+ pageInfo.setTotalList(projectList);
+ result.setData(pageInfo);
+ putMsg(result, Status.SUCCESS);
+ return result;
+ }
+
/**
* delete project by code
*
@@ -322,6 +426,11 @@ public class ProjectServiceImpl extends BaseServiceImpl implements ProjectServic
Result result = new Result();
Project project = projectMapper.queryByCode(projectCode);
+ boolean hasProjectAndWritePerm = hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
+ return result;
+ }
+
checkProjectAndAuth(result, loginUser, project, project == null ? 0L : project.getCode(), PROJECT_DELETE);
if (result.getCode() != Status.SUCCESS.getCode()) {
return result;
@@ -386,8 +495,8 @@ public class ProjectServiceImpl extends BaseServiceImpl implements ProjectServic
}
Project project = projectMapper.queryByCode(projectCode);
- boolean hasProjectAndPerm = hasProjectAndPerm(loginUser, project, result, PROJECT_UPDATE);
- if (!hasProjectAndPerm) {
+ boolean hasProjectAndWritePerm = hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
return result;
}
Project tempProject = projectMapper.queryByName(projectName);
@@ -417,6 +526,47 @@ public class ProjectServiceImpl extends BaseServiceImpl implements ProjectServic
return result;
}
+ /**
+ * query all project with authorized level
+ * @param loginUser login user
+ * @return project list
+ */
+ @Override
+ public Result queryProjectWithAuthorizedLevel(User loginUser, Integer userId) {
+ Result result = new Result();
+
+ Set<Integer> projectIds = resourcePermissionCheckService
+ .userOwnedResourceIdsAcquisition(AuthorizationType.PROJECTS, loginUser.getId(), logger);
+ List<Project> projectList = projectMapper.listAuthorizedProjects(
+ loginUser.getUserType().equals(UserType.ADMIN_USER) ? 0 : loginUser.getId(),
+ new ArrayList<>(projectIds));
+
+ List<Project> unauthorizedProjectsList = new ArrayList<>();
+ List<Project> authedProjectList = new ArrayList<>();
+ Set<Project> projectSet;
+ if (projectList != null && !projectList.isEmpty()) {
+ projectSet = new HashSet<>(projectList);
+ authedProjectList = projectMapper.queryAuthedProjectListByUserId(userId);
+ unauthorizedProjectsList = getUnauthorizedProjects(projectSet, authedProjectList);
+ }
+
+ for (int i = 0; i < authedProjectList.size(); i++) {
+ authedProjectList.get(i).setPerm(7);
+ }
+
+ for (int i = 0; i < unauthorizedProjectsList.size(); i++) {
+ unauthorizedProjectsList.get(i).setPerm(0);
+ }
+
+ List<Project> joined = new ArrayList<>();
+ joined.addAll(authedProjectList);
+ joined.addAll(unauthorizedProjectsList);
+
+ result.setData(joined);
+ putMsg(result, Status.SUCCESS);
+ return result;
+ }
+
/**
* query unauthorized project
*
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TaskDefinitionServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TaskDefinitionServiceImpl.java
index c12cbb53f1..1dbc91ad91 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TaskDefinitionServiceImpl.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TaskDefinitionServiceImpl.java
@@ -143,10 +143,11 @@ public class TaskDefinitionServiceImpl extends BaseServiceImpl implements TaskDe
long projectCode,
String taskDefinitionJson) {
Project project = projectMapper.queryByCode(projectCode);
- // check user access for project
+ // check if user have write perm for project
Map<String, Object> result =
projectService.checkProjectAndAuth(loginUser, project, projectCode, TASK_DEFINITION_CREATE);
- if (result.get(Constants.STATUS) != Status.SUCCESS) {
+ boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
return result;
}
@@ -285,10 +286,11 @@ public class TaskDefinitionServiceImpl extends BaseServiceImpl implements TaskDe
String taskDefinitionJsonObj,
String upstreamCodes) {
Project project = projectMapper.queryByCode(projectCode);
- // check user access for project
+ // check if user have write perm for project
Map<String, Object> result =
projectService.checkProjectAndAuth(loginUser, project, projectCode, TASK_DEFINITION_CREATE);
- if (result.get(Constants.STATUS) != Status.SUCCESS) {
+ boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
return result;
}
ProcessDefinition processDefinition = processDefinitionMapper.queryByCode(processDefinitionCode);
@@ -426,10 +428,16 @@ public class TaskDefinitionServiceImpl extends BaseServiceImpl implements TaskDe
/**
* Whether task definition can be deleted or not
*/
- private void taskCanDeleteValid(User user, TaskDefinition taskDefinition) {
+ private void taskCanDeleteValid(User user, TaskDefinition taskDefinition, User loginUser) {
// check user access for project
Project project = projectMapper.queryByCode(taskDefinition.getProjectCode());
projectService.checkProjectAndAuthThrowException(user, project, TASK_DEFINITION_DELETE);
+ // check if user have write perm for project
+ Map<String, Object> result = new HashMap<>();
+ boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
+ throw new ServiceException(Status.TASK_DEFINE_STATE_ONLINE, taskDefinition.getCode());
+ }
// Whether task relation workflow is online
if (processService.isTaskOnline(taskDefinition.getCode()) && taskDefinition.getFlag() == Flag.YES) {
@@ -466,7 +474,7 @@ public class TaskDefinitionServiceImpl extends BaseServiceImpl implements TaskDe
throw new ServiceException(Status.TASK_DEFINE_NOT_EXIST, taskCode);
}
- this.taskCanDeleteValid(loginUser, taskDefinition);
+ this.taskCanDeleteValid(loginUser, taskDefinition, loginUser);
int delete = taskDefinitionMapper.deleteByCode(taskCode);
if (delete <= 0) {
throw new ServiceException(Status.DELETE_TASK_DEFINE_BY_CODE_MSG_ERROR, taskDefinition.getCode());
@@ -683,11 +691,13 @@ public class TaskDefinitionServiceImpl extends BaseServiceImpl implements TaskDe
private TaskDefinitionLog updateTask(User loginUser, long projectCode, long taskCode, String taskDefinitionJsonObj,
Map<String, Object> result) {
Project project = projectMapper.queryByCode(projectCode);
- // check user access for project
- result.putAll(projectService.checkProjectAndAuth(loginUser, project, projectCode, TASK_DEFINITION_UPDATE));
- if (result.get(Constants.STATUS) != Status.SUCCESS) {
+
+ // check if user have write perm for project
+ boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
return null;
}
+
TaskDefinition taskDefinition = taskDefinitionMapper.queryByCode(taskCode);
if (taskDefinition == null) {
logger.error("Task definition does not exist, taskDefinitionCode:{}.", taskCode);
@@ -943,10 +953,11 @@ public class TaskDefinitionServiceImpl extends BaseServiceImpl implements TaskDe
@Override
public Map<String, Object> deleteByCodeAndVersion(User loginUser, long projectCode, long taskCode, int version) {
Project project = projectMapper.queryByCode(projectCode);
- // check user access for project
+ // check if user have write perm for project
Map<String, Object> result =
projectService.checkProjectAndAuth(loginUser, project, projectCode, TASK_DEFINITION_DELETE);
- if (result.get(Constants.STATUS) != Status.SUCCESS) {
+ boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ if (!hasProjectAndWritePerm) {
return result;
}
TaskDefinition taskDefinition = taskDefinitionMapper.queryByCode(taskCode);
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java
index 3b65634979..f200586fc6 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java
@@ -533,6 +533,97 @@ public class UsersServiceImpl extends BaseServiceImpl implements UsersService {
}
}
+ /**
+ * revoke the project permission for specified user by id
+ * @param loginUser Login user
+ * @param userId User id
+ * @param projectIds project id array
+ * @return
+ */
+ @Override
+ @Transactional(rollbackFor = RuntimeException.class)
+ public Map<String, Object> revokeProjectById(User loginUser, int userId, String projectIds) {
+ Map<String, Object> result = new HashMap<>();
+ result.put(Constants.STATUS, false);
+
+ if (resourcePermissionCheckService.functionDisabled()) {
+ putMsg(result, Status.FUNCTION_DISABLED);
+ return result;
+ }
+ // 1. only admin can operate
+ if (this.check(result, !this.isAdmin(loginUser), Status.USER_NO_OPERATION_PERM)) {
+ return result;
+ }
+
+ // 2. check if user is existed
+ User user = this.userMapper.selectById(userId);
+ if (user == null) {
+ this.putMsg(result, Status.USER_NOT_EXIST, userId);
+ return result;
+ }
+
+ Arrays.stream(projectIds.split(",")).distinct().forEach(projectId -> {
+ // 3. check if project is existed
+ Project project = this.projectMapper.queryDetailById(Integer.parseInt(projectId));
+ if (project == null) {
+ this.putMsg(result, Status.PROJECT_NOT_FOUND, Integer.parseInt(projectId));
+ } else {
+ // 4. delete the relationship between project and user
+ this.projectUserMapper.deleteProjectRelation(project.getId(), user.getId());
+ }
+ });
+
+ this.putMsg(result, Status.SUCCESS);
+ return result;
+ }
+
+ /**
+ * grant project with read permission
+ *
+ * @param loginUser login user
+ * @param userId user id
+ * @param projectIds project id array
+ * @return grant result code
+ */
+ @Override
+ @Transactional(rollbackFor = RuntimeException.class)
+ public Map<String, Object> grantProjectWithReadPerm(User loginUser, int userId, String projectIds) {
+ Map<String, Object> result = new HashMap<>();
+ result.put(Constants.STATUS, false);
+
+ if (resourcePermissionCheckService.functionDisabled()) {
+ putMsg(result, Status.FUNCTION_DISABLED);
+ return result;
+ }
+ // check exist
+ User tempUser = userMapper.selectById(userId);
+ if (tempUser == null) {
+ putMsg(result, Status.USER_NOT_EXIST, userId);
+ return result;
+ }
+
+ if (check(result, StringUtils.isEmpty(projectIds), Status.SUCCESS)) {
+ return result;
+ }
+ Arrays.stream(projectIds.split(Constants.COMMA)).distinct().forEach(projectId -> {
+ ProjectUser projectUserOld = projectUserMapper.queryProjectRelation(Integer.parseInt(projectId), userId);
+ if (projectUserOld != null) {
+ projectUserMapper.deleteProjectRelation(Integer.parseInt(projectId), userId);
+ }
+ Date now = new Date();
+ ProjectUser projectUser = new ProjectUser();
+ projectUser.setUserId(userId);
+ projectUser.setProjectId(Integer.parseInt(projectId));
+ projectUser.setPerm(Constants.READ_PERMISSION);
+ projectUser.setCreateTime(now);
+ projectUser.setUpdateTime(now);
+ projectUserMapper.insert(projectUser);
+ });
+ putMsg(result, Status.SUCCESS);
+
+ return result;
+ }
+
/**
* grant project
*
@@ -559,13 +650,15 @@ public class UsersServiceImpl extends BaseServiceImpl implements UsersService {
return result;
}
- projectUserMapper.deleteProjectRelation(0, userId);
-
if (check(result, StringUtils.isEmpty(projectIds), Status.SUCCESS)) {
logger.warn("Parameter projectIds is empty.");
return result;
}
Arrays.stream(projectIds.split(",")).distinct().forEach(projectId -> {
+ ProjectUser projectUserOld = projectUserMapper.queryProjectRelation(Integer.parseInt(projectId), userId);
+ if (projectUserOld != null) {
+ projectUserMapper.deleteProjectRelation(Integer.parseInt(projectId), userId);
+ }
Date now = new Date();
ProjectUser projectUser = new ProjectUser();
projectUser.setUserId(userId);
diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionServiceTest.java
index 31502b917e..de8a58f619 100644
--- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionServiceTest.java
+++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionServiceTest.java
@@ -779,6 +779,7 @@ public class ProcessDefinitionServiceTest extends BaseServiceTestTool {
Mockito.when(projectMapper.queryByCode(projectCode)).thenReturn(getProject(projectCode));
Mockito.when(projectService.checkProjectAndAuth(user, project, projectCode, WORKFLOW_UPDATE))
.thenReturn(result);
+ Mockito.when(projectService.hasProjectAndWritePerm(user, project, result)).thenReturn(true);
try {
processDefinitionService.updateProcessDefinition(user, projectCode, "test", 1,
diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProjectServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProjectServiceTest.java
index 5ad77a3e87..f2b3d4d16b 100644
--- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProjectServiceTest.java
+++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProjectServiceTest.java
@@ -22,11 +22,14 @@ import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationCon
import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.PROJECT_CREATE;
import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.PROJECT_DELETE;
import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.PROJECT_UPDATE;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.permission.ResourcePermissionCheckService;
import org.apache.dolphinscheduler.api.service.impl.BaseServiceImpl;
import org.apache.dolphinscheduler.api.service.impl.ProjectServiceImpl;
+import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.enums.AuthorizationType;
@@ -62,6 +65,9 @@ import org.mockito.quality.Strictness;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
/**
* project service test
**/
@@ -206,6 +212,66 @@ public class ProjectServiceTest {
Assertions.assertTrue(checkResult);
}
+ @Test
+ public void testQueryProjectWithAuthorizedLevelListPaging() {
+ IPage<Project> page = new Page<>(1, 10);
+ page.setTotal(1L);
+ page.setRecords(getList());
+
+ User loginUser = getLoginUser();
+ Integer pageSize = 10;
+ Integer pageNo = 1;
+ String searchVal = "testVal";
+ Result result = new Result();
+ Mockito.when(projectMapper.queryProjectListPaging(any(Page.class), Mockito.anyList(), eq(searchVal)))
+ .thenReturn(page);
+
+ Set<Integer> allProjectIds = new HashSet();
+ allProjectIds.add(1);
+ Mockito.when(resourcePermissionCheckService.userOwnedResourceIdsAcquisition(AuthorizationType.PROJECTS,
+ loginUser.getId(), projectLogger)).thenReturn(allProjectIds);
+
+ // SUCCESS
+ result = projectService.queryProjectWithAuthorizedLevelListPaging(loginUser.getId(), loginUser, pageSize,
+ pageNo, searchVal);
+ logger.info(result.toString());
+ PageInfo<Project> pageInfo = (PageInfo<Project>) result.getData();
+ Assertions.assertTrue(CollectionUtils.isNotEmpty(pageInfo.getTotalList()));
+ }
+
+ @Test
+ public void testHasProjectAndWritePerm() {
+
+ // Mockito.when(projectUserMapper.queryProjectRelation(1, 1)).thenReturn(getProjectUser());
+ User loginUser = getLoginUser();
+ Project project = getProject();
+ Map<String, Object> result = new HashMap<>();
+ // not exist user
+ User tempUser = new User();
+ tempUser.setId(Integer.MAX_VALUE);
+ tempUser.setUserType(UserType.GENERAL_USER);
+ Mockito.when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.PROJECTS,
+ new Object[]{project.getId()},
+ tempUser.getId(), null, baseServiceLogger)).thenReturn(true);
+ boolean checkResult = projectService.hasProjectAndWritePerm(tempUser, project, result);
+ logger.info(result.toString());
+ Assertions.assertFalse(checkResult);
+
+ // success
+ result = new HashMap<>();
+ project.setUserId(1);
+ loginUser.setUserType(UserType.ADMIN_USER);
+ Mockito.when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.PROJECTS,
+ new Object[]{project.getId()},
+ loginUser.getId(), null, baseServiceLogger)).thenReturn(true);
+ Mockito.when(resourcePermissionCheckService.resourcePermissionCheck(AuthorizationType.PROJECTS,
+ new Object[]{project.getId()},
+ 0, baseServiceLogger)).thenReturn(true);
+ checkResult = projectService.hasProjectAndWritePerm(loginUser, project, result);
+ logger.info(result.toString());
+ Assertions.assertTrue(checkResult);
+ }
+
@Test
public void testDeleteProject() {
User loginUser = getLoginUser();
@@ -213,10 +279,10 @@ public class ProjectServiceTest {
Mockito.when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.PROJECTS,
new Object[]{1}, loginUser.getId(),
PROJECT_DELETE, baseServiceLogger)).thenReturn(true);
- // PROJECT_NOT_FOUNT
+ // PROJECT_NOT_FOUND
Result result = projectService.deleteProject(loginUser, 11L);
logger.info(result.toString());
- Assertions.assertTrue(Status.PROJECT_NOT_EXIST.getCode() == result.getCode());
+ Assertions.assertTrue(Status.PROJECT_NOT_FOUND.getCode() == result.getCode());
loginUser.setId(2);
// USER_NO_OPERATION_PROJECT_PERM
Mockito.when(resourcePermissionCheckService.resourcePermissionCheck(AuthorizationType.PROJECTS, new Object[]{1},
@@ -224,7 +290,7 @@ public class ProjectServiceTest {
baseServiceLogger)).thenReturn(true);
result = projectService.deleteProject(loginUser, 1L);
logger.info(result.toString());
- Assertions.assertTrue(Status.USER_NO_OPERATION_PROJECT_PERM.getCode() == result.getCode());
+ Assertions.assertTrue(Status.USER_NO_WRITE_PROJECT_PERM.getCode() == result.getCode());
// DELETE_PROJECT_ERROR_DEFINES_NOT_NULL
Mockito.when(processDefinitionMapper.queryAllDefinitionList(1L)).thenReturn(getProcessDefinitions());
@@ -418,6 +484,40 @@ public class ProjectServiceTest {
}
+ @Test
+ public void testQueryProjectWithAuthorizedLevel() {
+ Set<Integer> set = new HashSet();
+ set.add(1);
+ // test admin user
+ User loginUser = new User();
+ loginUser.setUserType(UserType.ADMIN_USER);
+ loginUser.setId(1);
+ List<Integer> list = new ArrayList<>(1);
+ list.add(1);
+ Mockito.when(resourcePermissionCheckService.userOwnedResourceIdsAcquisition(AuthorizationType.PROJECTS,
+ loginUser.getId(), projectLogger)).thenReturn(set);
+ Mockito.when(projectMapper.listAuthorizedProjects(
+ loginUser.getUserType().equals(UserType.ADMIN_USER) ? 0 : loginUser.getId(), list))
+ .thenReturn(getList());
+ Result result = projectService.queryProjectWithAuthorizedLevel(loginUser, 2);
+ logger.info(result.toString());
+ List<Project> projects = (List<Project>) result.getData();
+ Assertions.assertTrue(CollectionUtils.isNotEmpty(projects));
+
+ // test non-admin user
+ loginUser.setId(2);
+ loginUser.setUserType(UserType.GENERAL_USER);
+ Mockito.when(resourcePermissionCheckService.userOwnedResourceIdsAcquisition(AuthorizationType.PROJECTS,
+ loginUser.getId(), projectLogger)).thenReturn(set);
+ Mockito.when(projectMapper.listAuthorizedProjects(
+ loginUser.getUserType().equals(UserType.ADMIN_USER) ? 0 : loginUser.getId(), list))
+ .thenReturn(getList());
+ result = projectService.queryProjectWithAuthorizedLevel(loginUser, 3);
+ logger.info(result.toString());
+ projects = (List<Project>) result.getData();
+ Assertions.assertTrue(CollectionUtils.isNotEmpty(projects));
+ }
+
@Test
public void testQueryUnauthorizedProject() {
Set<Integer> set = new HashSet();
diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/TaskDefinitionServiceImplTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/TaskDefinitionServiceImplTest.java
index 798367c422..0c271ace6f 100644
--- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/TaskDefinitionServiceImplTest.java
+++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/TaskDefinitionServiceImplTest.java
@@ -141,10 +141,6 @@ public class TaskDefinitionServiceImplTest {
+ "\\\\\\\"failedNode\\\\\\\":[\\\\\\\"\\\\\\\"]}\\\",\\\"dependence\\\":{}}\",\"flag\":0,\"taskPriority\":0,"
+ "\"workerGroup\":\"default\",\"failRetryTimes\":0,\"failRetryInterval\":0,\"timeoutFlag\":0,"
+ "\"timeoutNotifyStrategy\":0,\"timeout\":0,\"delayTime\":0,\"resourceIds\":\"\"}]";
- List<TaskDefinitionLog> taskDefinitions = JSONUtils.toList(createTaskDefinitionJson, TaskDefinitionLog.class);
- Mockito.when(processService.saveTaskDefine(user, PROJECT_CODE, taskDefinitions, Boolean.TRUE))
- .thenReturn(1);
- Mockito.when(taskPluginManager.checkTaskParameters(Mockito.any())).thenReturn(true);
Map<String, Object> relation = taskDefinitionService
.createTaskDefinition(user, PROJECT_CODE, createTaskDefinitionJson);
Assertions.assertEquals(Status.SUCCESS, relation.get(Constants.STATUS));
@@ -166,8 +162,7 @@ public class TaskDefinitionServiceImplTest {
Map<String, Object> result = new HashMap<>();
putMsg(result, Status.SUCCESS, PROJECT_CODE);
- Mockito.when(projectService.checkProjectAndAuth(user, project, PROJECT_CODE, TASK_DEFINITION_UPDATE))
- .thenReturn(result);
+ Mockito.when(projectService.hasProjectAndWritePerm(user, project, new HashMap<>())).thenReturn(true);
Mockito.when(processService.isTaskOnline(TASK_CODE)).thenReturn(Boolean.FALSE);
Mockito.when(taskDefinitionMapper.queryByCode(TASK_CODE)).thenReturn(new TaskDefinition());
@@ -212,6 +207,7 @@ public class TaskDefinitionServiceImplTest {
// error delete single task definition object
Mockito.when(taskDefinitionMapper.queryByCode(TASK_CODE)).thenReturn(getTaskDefinition());
Mockito.when(taskDefinitionMapper.deleteByCode(TASK_CODE)).thenReturn(0);
+ Mockito.when(projectService.hasProjectAndWritePerm(user, project, new HashMap<>())).thenReturn(true);
exception = Assertions.assertThrows(ServiceException.class,
() -> taskDefinitionService.deleteTaskDefinitionByCode(user, TASK_CODE));
Assertions.assertEquals(Status.DELETE_TASK_DEFINE_BY_CODE_MSG_ERROR.getCode(),
diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java
index aae27f88b2..8a9c6506be 100644
--- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java
+++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java
@@ -369,6 +369,27 @@ public class UsersServiceTest {
Assertions.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
}
+ @Test
+ public void testGrantProjectWithReadPerm() {
+ String projectIds = "100000,120000";
+ User loginUser = new User();
+ int userId = 3;
+
+ // user not exist
+ loginUser.setId(1);
+ loginUser.setUserType(UserType.ADMIN_USER);
+ when(userMapper.selectById(userId)).thenReturn(null);
+ Map<String, Object> result = usersService.grantProjectWithReadPerm(loginUser, userId, projectIds);
+ logger.info(result.toString());
+ Assertions.assertEquals(Status.USER_NOT_EXIST, result.get(Constants.STATUS));
+
+ // SUCCESS
+ when(userMapper.selectById(userId)).thenReturn(getUser());
+ result = usersService.grantProjectWithReadPerm(loginUser, userId, projectIds);
+ logger.info(result.toString());
+ Assertions.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
+ }
+
@Test
public void testGrantProjectByCode() {
// Mock Project, User
@@ -440,6 +461,31 @@ public class UsersServiceTest {
Assertions.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
}
+ @Test
+ public void testRevokeProjectById() {
+ Mockito.when(this.userMapper.selectById(1)).thenReturn(this.getUser());
+
+ String projectId = "100000";
+
+ // user no permission
+ User loginUser = new User();
+ Map<String, Object> result = this.usersService.revokeProjectById(loginUser, 1, projectId);
+ logger.info(result.toString());
+ Assertions.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS));
+
+ // user not exist
+ loginUser.setUserType(UserType.ADMIN_USER);
+ result = this.usersService.revokeProjectById(loginUser, 2, projectId);
+ logger.info(result.toString());
+ Assertions.assertEquals(Status.USER_NOT_EXIST, result.get(Constants.STATUS));
+
+ // success
+ Mockito.when(this.projectMapper.queryByCode(Mockito.anyLong())).thenReturn(new Project());
+ result = this.usersService.revokeProjectById(loginUser, 1, projectId);
+ logger.info(result.toString());
+ Assertions.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
+ }
+
@Test
public void testGrantResources() {
String resourceIds = "100000,120000";
diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ProjectUserMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ProjectUserMapper.java
index b5496c438d..38c4a2b4c9 100644
--- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ProjectUserMapper.java
+++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ProjectUserMapper.java
@@ -29,7 +29,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface ProjectUserMapper extends BaseMapper<ProjectUser> {
/**
- * delte prject user relation
+ * delete project user relation
*
* @param projectId projectId
* @param userId userId
diff --git a/dolphinscheduler-ui/src/common/column-width-config.ts b/dolphinscheduler-ui/src/common/column-width-config.ts
index 7df8dbc321..d292a9a84f 100644
--- a/dolphinscheduler-ui/src/common/column-width-config.ts
+++ b/dolphinscheduler-ui/src/common/column-width-config.ts
@@ -95,6 +95,9 @@ export const COLUMN_WIDTH_CONFIG = {
tag: {
width: 160
},
+ checkbox:{
+ width: 20
+ },
copy: {
width: 50
}
diff --git a/dolphinscheduler-ui/src/locales/en_US/project.ts b/dolphinscheduler-ui/src/locales/en_US/project.ts
index 115cb70967..0aa20551f7 100644
--- a/dolphinscheduler-ui/src/locales/en_US/project.ts
+++ b/dolphinscheduler-ui/src/locales/en_US/project.ts
@@ -36,7 +36,11 @@ export default {
delete: 'Delete',
confirm: 'Confirm',
cancel: 'Cancel',
- delete_confirm: 'Delete?'
+ delete_confirm: 'Delete?',
+ authorize_level:'Authorize Level',
+ no_permission: 'No Permission',
+ read_permission: 'Read Permission',
+ all_permission: 'All Permission',
},
workflow: {
on_line: 'Online',
diff --git a/dolphinscheduler-ui/src/locales/en_US/security.ts b/dolphinscheduler-ui/src/locales/en_US/security.ts
index 2dbb66fe84..4318cdb0c8 100644
--- a/dolphinscheduler-ui/src/locales/en_US/security.ts
+++ b/dolphinscheduler-ui/src/locales/en_US/security.ts
@@ -150,6 +150,9 @@ export default {
datasource: 'Datasource',
udf: 'UDF Function',
namespace: 'Namespace',
+ revoke_auth: 'Revoke',
+ grant_read: 'Grant Read',
+ grant_all:'Grant All',
authorize_project: 'Project Authorize',
authorize_resource: 'Resource Authorize',
authorize_namespace: 'Namespace Authorize',
diff --git a/dolphinscheduler-ui/src/locales/zh_CN/project.ts b/dolphinscheduler-ui/src/locales/zh_CN/project.ts
index 31c5c64617..fe9f14b279 100644
--- a/dolphinscheduler-ui/src/locales/zh_CN/project.ts
+++ b/dolphinscheduler-ui/src/locales/zh_CN/project.ts
@@ -36,7 +36,11 @@ export default {
delete: '删除',
confirm: '确定',
cancel: '取消',
- delete_confirm: '确定删除吗?'
+ delete_confirm: '确定删除吗?',
+ authorize_level:'权限等级',
+ no_permission: '无权限',
+ read_permission: '读权限',
+ all_permission: '所有权限',
},
workflow: {
on_line: '线上',
diff --git a/dolphinscheduler-ui/src/locales/zh_CN/security.ts b/dolphinscheduler-ui/src/locales/zh_CN/security.ts
index 9135ba78e4..995293ec68 100644
--- a/dolphinscheduler-ui/src/locales/zh_CN/security.ts
+++ b/dolphinscheduler-ui/src/locales/zh_CN/security.ts
@@ -148,6 +148,9 @@ export default {
datasource: '数据源',
udf: 'UDF函数',
namespace: '命名空间',
+ revoke_auth: '撤销权限',
+ grant_read: '授予读权限',
+ grant_all:'授予所有权限',
authorize_project: '项目授权',
authorize_resource: '资源授权',
authorize_namespace: '命名空间授权',
diff --git a/dolphinscheduler-ui/src/service/modules/projects/index.ts b/dolphinscheduler-ui/src/service/modules/projects/index.ts
index 69e097c7b8..e426d47f5e 100644
--- a/dolphinscheduler-ui/src/service/modules/projects/index.ts
+++ b/dolphinscheduler-ui/src/service/modules/projects/index.ts
@@ -16,7 +16,7 @@
*/
import { axios } from '@/service/service'
-import { ListReq, ProjectsReq, UserIdReq, UpdateProjectsReq } from './types'
+import { ListReq, ListIdReq, ProjectsReq, UserIdReq, UpdateProjectsReq } from './types'
export function queryProjectListPaging(params: ListReq): any {
return axios({
@@ -26,6 +26,14 @@ export function queryProjectListPaging(params: ListReq): any {
})
}
+export function queryProjectWithAuthorizedLevelListPaging(params: ListIdReq): any {
+ return axios({
+ url: '/projects/project-with-authorized-level-list-paging',
+ method: 'get',
+ params
+ })
+}
+
export function createProject(data: ProjectsReq): any {
return axios({
url: '/projects',
@@ -64,6 +72,14 @@ export function queryUnauthorizedProject(params: UserIdReq): any {
})
}
+export function queryProjectWithAuthorizedLevel(params: UserIdReq): any {
+ return axios({
+ url: '/projects/project-with-authorized-level',
+ method: 'get',
+ params
+ })
+}
+
export function queryProjectByCode(code: number): any {
return axios({
url: `/projects/${code}`,
diff --git a/dolphinscheduler-ui/src/service/modules/projects/types.ts b/dolphinscheduler-ui/src/service/modules/projects/types.ts
index 6b02d52ba0..3d0d824c8f 100644
--- a/dolphinscheduler-ui/src/service/modules/projects/types.ts
+++ b/dolphinscheduler-ui/src/service/modules/projects/types.ts
@@ -21,6 +21,13 @@ interface ListReq {
searchVal?: string
}
+interface ListIdReq {
+ userId?: number
+ pageNo: number
+ pageSize: number
+ searchVal?: string
+}
+
interface ProjectsReq {
description?: string
projectName: string
@@ -59,6 +66,7 @@ interface ProjectRes {
export {
ListReq,
+ ListIdReq,
ProjectsReq,
UserIdReq,
UpdateProjectsReq,
diff --git a/dolphinscheduler-ui/src/service/modules/users/index.ts b/dolphinscheduler-ui/src/service/modules/users/index.ts
index 9a1313cbfb..ce3806e4af 100644
--- a/dolphinscheduler-ui/src/service/modules/users/index.ts
+++ b/dolphinscheduler-ui/src/service/modules/users/index.ts
@@ -97,6 +97,14 @@ export function grantResource(data: GrantResourceReq) {
})
}
+export function revokeProjectById(data: GrantProject) {
+ return axios({
+ url: '/users/revoke-project-by-id',
+ method: 'post',
+ data
+ })
+}
+
export function grantProject(data: GrantProject) {
return axios({
url: '/users/grant-project',
@@ -105,6 +113,14 @@ export function grantProject(data: GrantProject) {
})
}
+export function grantProjectWithReadPerm(data: GrantProject) {
+ return axios({
+ url: 'users/grant-project-with-read-perm',
+ method: 'post',
+ data
+ })
+}
+
export function grantProjectByCode(data: ProjectCodeReq & UserIdReq): any {
return axios({
url: '/users/grant-project-by-code',
diff --git a/dolphinscheduler-ui/src/views/security/user-manage/components/authorize-modal.tsx b/dolphinscheduler-ui/src/views/security/user-manage/components/authorize-modal.tsx
index bce9c567c6..e0855d9d5b 100644
--- a/dolphinscheduler-ui/src/views/security/user-manage/components/authorize-modal.tsx
+++ b/dolphinscheduler-ui/src/views/security/user-manage/components/authorize-modal.tsx
@@ -15,19 +15,26 @@
* limitations under the License.
*/
-import { defineComponent, PropType, toRefs, watch } from 'vue'
+import { defineComponent, PropType, toRefs, watch} from 'vue'
import { useI18n } from 'vue-i18n'
import {
+ NInput,
+ NButton,
+ NIcon,
NTransfer,
NSpace,
NRadioGroup,
NRadioButton,
- NTreeSelect
+ NTreeSelect,
+ NDataTable,
+ NPagination
} from 'naive-ui'
import { useAuthorize } from './use-authorize'
import Modal from '@/components/modal'
import styles from '../index.module.scss'
import type { TAuthType } from '../types'
+import { useColumns } from './use-columns'
+import { SearchOutlined } from '@vicons/antd'
const props = {
show: {
@@ -43,14 +50,13 @@ const props = {
default: 'auth_project'
}
}
-
export const AuthorizeModal = defineComponent({
name: 'authorize-project-modal',
props,
emits: ['cancel'],
setup(props, ctx) {
const { t } = useI18n()
- const { state, onInit, onSave } = useAuthorize()
+ const { state, onInit, onSave, getProjects, revokeProjectByIdRequest, grantProjectRequest, grantProjectWithReadPermRequest, requestData, handleChangePageSize } = useAuthorize()
const onCancel = () => {
ctx.emit('cancel')
}
@@ -59,6 +65,20 @@ export const AuthorizeModal = defineComponent({
if (result) onCancel()
}
+ const onRevokeProject = () => {
+ revokeProjectByIdRequest(props.userId, state.projectIds)
+ }
+ const onGrantReadPerm = () => {
+ grantProjectWithReadPermRequest(props.userId, state.projectIds)
+ }
+ const onGrantAllPerm = () => {
+ grantProjectRequest(props.userId, state.projectIds)
+ }
+
+ const { columnsRef } = useColumns()
+ const handleCheck = (rowKeys: Array<number>) => {
+ state.projectIds = rowKeys.join()
+ }
watch(
() => props.show,
() => {
@@ -70,14 +90,23 @@ export const AuthorizeModal = defineComponent({
return {
t,
+ columnsRef,
+ rowKey: (row: any) => row.id,
...toRefs(state),
onCancel,
- onConfirm
+ onConfirm,
+ getProjects,
+ handleCheck,
+ requestData,
+ handleChangePageSize,
+ onRevokeProject,
+ onGrantReadPerm,
+ onGrantAllPerm
}
},
- render(props: { type: TAuthType }) {
+ render(props: { type: TAuthType, userId: number }) {
const { t } = this
- const { type } = props
+ const { type, userId } = props
return (
<Modal
show={this.show}
@@ -89,13 +118,54 @@ export const AuthorizeModal = defineComponent({
cancelClassName='btn-cancel'
>
{type === 'authorize_project' && (
- <NTransfer
+
+ <NSpace vertical>
+ <NSpace>
+ <NButton size='small' type='primary' onClick={this.onRevokeProject}>
+ {t('security.user.revoke_auth')}
+ </NButton>
+ <NButton size='small' type='primary' onClick={this.onGrantReadPerm}>
+ {t('security.user.grant_read')}
+ </NButton>
+ <NButton size='small' type='primary' onClick={this.onGrantAllPerm}>
+ {t('security.user.grant_all')}
+ </NButton>
+ <NInput
+ size='small'
+ placeholder={t('project.list.project_tips')}
+ clearable
+ v-model:value={this.searchVal}
+ />
+ {/* <NButton size='small' type='primary' onClick={this.handleSearch}> */}
+ <NButton size='small' type='primary' onClick={() => this.getProjects(userId)}>
+ <NIcon>
+ <SearchOutlined />
+ </NIcon>
+ </NButton>
+ </NSpace>
+ <NDataTable
virtualScroll
- options={this.unauthorizedProjects}
- filterable
- v-model={[this.authorizedProjects, 'value']}
- class={styles.transfer}
+ row-class-name='items'
+ columns={this.columnsRef.columns}
+ data={this.projectWithAuthorizedLevel}
+ loading={this.loading}
+ max-height="250"
+ row-key={this.rowKey}
+ on-update:checked-row-keys={this.handleCheck}
/>
+ <div class={styles.pagination}>
+ <NPagination
+ v-model:page={this.pagination.page}
+ v-model:page-size={this.pagination.pageSize}
+ page-count={this.pagination.totalPage}
+ show-size-picker
+ page-sizes={[5, 10]}
+ show-quick-jumper
+ onUpdatePage={this.requestData}
+ onUpdatePageSize={this.handleChangePageSize}
+ />
+ </div>
+ </NSpace>
)}
{type === 'authorize_datasource' && (
<NTransfer
diff --git a/dolphinscheduler-ui/src/views/security/user-manage/components/use-authorize.ts b/dolphinscheduler-ui/src/views/security/user-manage/components/use-authorize.ts
index 4d7d26b41f..e1cfbd9438 100644
--- a/dolphinscheduler-ui/src/views/security/user-manage/components/use-authorize.ts
+++ b/dolphinscheduler-ui/src/views/security/user-manage/components/use-authorize.ts
@@ -16,8 +16,7 @@
*/
import { reactive } from 'vue'
import {
- queryAuthorizedProject,
- queryUnauthorizedProject
+ queryProjectWithAuthorizedLevelListPaging
} from '@/service/modules/projects'
import {
authedDatasource,
@@ -36,17 +35,22 @@ import {
import {
grantProject,
grantResource,
+ grantProjectWithReadPerm,
grantDataSource,
grantUDFFunc,
- grantNamespaceFunc
+ grantNamespaceFunc,
+ revokeProjectById,
} from '@/service/modules/users'
import utils from '@/utils'
-import type { TAuthType, IResourceOption, IOption } from '../types'
+import type { TAuthType, IResourceOption, IOption, IRecord } from '../types'
export function useAuthorize() {
const state = reactive({
saving: false,
loading: false,
+ projectIds: '',
+ currentRecord: {} as IRecord | null,
+ projectWithAuthorizedLevel: [],
authorizedProjects: [] as number[],
unauthorizedProjects: [] as IOption[],
authorizedDatasources: [] as number[],
@@ -59,26 +63,69 @@ export function useAuthorize() {
fileResources: [] as IResourceOption[],
udfResources: [] as IResourceOption[],
authorizedFileResources: [] as number[],
- authorizedUdfResources: [] as number[]
+ authorizedUdfResources: [] as number[],
+ pagination: {
+ pageSize: 5,
+ page: 1,
+ totalPage: 0
+ },
+ searchVal: '',
+ userId: 0
})
const getProjects = async (userId: number) => {
if (state.loading) return
state.loading = true
- const projects = await Promise.all([
- queryAuthorizedProject({ userId }),
- queryUnauthorizedProject({ userId })
- ])
+ if (userId) {
+ state.userId = userId
+ }
+
+ const projectsList = await queryProjectWithAuthorizedLevelListPaging({
+ userId,
+ searchVal: state.searchVal,
+ pageSize: state.pagination.pageSize,
+ pageNo: state.pagination.page
+ })
state.loading = false
- state.authorizedProjects = projects[0].map(
- (item: { name: string; id: number }) => item.id
- )
- state.unauthorizedProjects = [...projects[0], ...projects[1]].map(
- (item: { name: string; id: number }) => ({
- label: item.name,
- value: item.id
- })
- )
+ if (!projectsList) throw Error()
+ state.pagination.totalPage = projectsList.totalPage
+ state.projectWithAuthorizedLevel = projectsList.totalList
+ return state.projectWithAuthorizedLevel
+ }
+
+ const requestData = async (page: number) => {
+ state.pagination.page = page
+ await getProjects(state.userId)
+ }
+
+ const handleChangePageSize = async (pageSize: number) => {
+ state.pagination.page = 1
+ state.pagination.pageSize = pageSize
+ await getProjects(state.userId)
+ }
+
+ const revokeProjectByIdRequest = async (userId: number, projectIds: string) => {
+ await revokeProjectById({
+ userId,
+ projectIds: projectIds
+ })
+ await getProjects(userId)
+ }
+
+ const grantProjectRequest = async (userId: number, projectIds: string) => {
+ await grantProject({
+ userId,
+ projectIds: projectIds
+ })
+ await getProjects(userId)
+ }
+
+ const grantProjectWithReadPermRequest = async (userId: number, projectIds: string) => {
+ await grantProjectWithReadPerm({
+ userId,
+ projectIds: projectIds
+ })
+ await getProjects(userId)
}
const getDatasources = async (userId: number) => {
@@ -216,12 +263,6 @@ export function useAuthorize() {
const onSave = async (type: TAuthType, userId: number) => {
if (state.saving) return false
state.saving = true
- if (type === 'authorize_project') {
- await grantProject({
- userId,
- projectIds: state.authorizedProjects.join(',')
- })
- }
if (type === 'authorize_datasource') {
await grantDataSource({
userId,
@@ -281,5 +322,5 @@ export function useAuthorize() {
return true
}
- return { state, onInit, onSave }
+ return { state, onInit, onSave, getProjects, revokeProjectByIdRequest, grantProjectRequest, grantProjectWithReadPermRequest, requestData, handleChangePageSize }
}
diff --git a/dolphinscheduler-ui/src/views/security/user-manage/components/use-columns.ts b/dolphinscheduler-ui/src/views/security/user-manage/components/use-columns.ts
new file mode 100644
index 0000000000..9e7a609136
--- /dev/null
+++ b/dolphinscheduler-ui/src/views/security/user-manage/components/use-columns.ts
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ref, watch, onMounted } from 'vue'
+import { useI18n } from 'vue-i18n'
+import {
+ COLUMN_WIDTH_CONFIG,
+ calculateTableWidth,
+ DefaultTableWidth
+} from '@/common/column-width-config'
+import type { TableColumns } from '../types'
+
+// const { t } = useI18n()
+const PERM_LIST = [
+ {
+ label: 'project.list.no_permission',
+ value: 0
+ },
+ {
+ label: 'project.list.read_permission',
+ value: 2
+ },
+ {
+ label: 'project.list.all_permission',
+ value: 7
+ }
+]
+
+
+export function useColumns() {
+ const { t } = useI18n()
+
+ const columnsRef = ref({
+ columns: [] as TableColumns,
+ tableWidth: DefaultTableWidth
+ })
+
+ const createColumns = () => {
+ const columns: any = [
+ {
+ type: 'selection',
+ key: 'selection',
+ ...COLUMN_WIDTH_CONFIG['checkbox']
+ },
+ {
+ title: t('project.list.project_name'),
+ key: 'name',
+ ...COLUMN_WIDTH_CONFIG['size']
+ },
+ {
+ title: t('project.list.authorize_level'),
+ key: 'perm',
+ render: (record: any):any => {
+ return PERM_LIST.filter(item => item.value == record.perm).map(item => t(item.label))
+ },
+ ...COLUMN_WIDTH_CONFIG['index']
+ }
+ ]
+ columnsRef.value = {
+ columns,
+ tableWidth: calculateTableWidth(columns)
+ }
+ }
+
+ onMounted(() => {
+ createColumns()
+ })
+
+ watch(useI18n().locale, () => {
+ createColumns()
+ })
+
+ return {
+ columnsRef,
+ createColumns
+ }
+}
diff --git a/dolphinscheduler-ui/src/views/security/user-manage/index.module.scss b/dolphinscheduler-ui/src/views/security/user-manage/index.module.scss
index 68d62fdd11..4bdd2c4c60 100644
--- a/dolphinscheduler-ui/src/views/security/user-manage/index.module.scss
+++ b/dolphinscheduler-ui/src/views/security/user-manage/index.module.scss
@@ -18,3 +18,8 @@
.transfer {
width: 100%;
}
+.pagination {
+ margin-top: 10px;
+ display: flex;
+ justify-content: center;
+}