You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
15 KiB
356 lines
15 KiB
/* |
|
* Copyright (C), 2018-2021 |
|
* Project: starter |
|
* FileName: DingTalkUserManager |
|
* Author: xx |
|
* Date: 2021/4/21 16:18 |
|
*/ |
|
package com.fr.plugin.dingtalksyn.user; |
|
|
|
import com.dingtalk.api.DefaultDingTalkClient; |
|
import com.dingtalk.api.DingTalkClient; |
|
import com.dingtalk.api.request.*; |
|
import com.dingtalk.api.response.*; |
|
import com.fanruan.api.decision.user.UserKit; |
|
import com.fanruan.api.i18n.I18nKit; |
|
import com.fanruan.api.log.LogKit; |
|
import com.fanruan.api.util.StringKit; |
|
import com.fr.decision.authority.AuthorityContext; |
|
import com.fr.decision.authority.base.constant.SoftRoleType; |
|
import com.fr.decision.authority.base.constant.type.operation.ManualOperationType; |
|
import com.fr.decision.authority.data.CustomRole; |
|
import com.fr.decision.authority.data.Department; |
|
import com.fr.decision.record.OperateMessage; |
|
import com.fr.decision.webservice.bean.user.RoleBean; |
|
import com.fr.decision.webservice.bean.user.UserBean; |
|
import com.fr.decision.webservice.exception.general.DuplicatedNameException; |
|
import com.fr.decision.webservice.utils.ControllerFactory; |
|
import com.fr.decision.webservice.v10.user.CustomRoleService; |
|
import com.fr.decision.webservice.v10.user.DepartmentService; |
|
import com.fr.decision.webservice.v10.user.UserService; |
|
import com.fr.general.ComparatorUtils; |
|
import com.fr.intelli.record.MetricRegistry; |
|
import com.fr.plugin.dingtalksyn.config.DingSynConfig; |
|
import com.fr.plugin.dingtalksyn.kit.UserServiceKit; |
|
import com.fr.stable.StableUtils; |
|
import com.fr.stable.query.QueryFactory; |
|
import com.fr.stable.query.condition.QueryCondition; |
|
import com.fr.stable.query.restriction.Restriction; |
|
import com.fr.stable.query.restriction.RestrictionFactory; |
|
import com.taobao.api.ApiException; |
|
|
|
import java.util.ArrayList; |
|
import java.util.Collections; |
|
import java.util.List; |
|
|
|
/** |
|
* <Function Description><br> |
|
* <DingTalkUserManager> |
|
* |
|
* @author xx |
|
* @since 1.0.0 |
|
*/ |
|
public final class DingTalkUserManager { |
|
public static final String DECISION_DEP_ROOT = "decision-dep-root"; |
|
|
|
public static final String GETTOKEN = "https://xx/gettoken"; |
|
public static final String DEPARTMENT_LIST = "https://xx/topapi/v2/department/listsub"; |
|
public static final String GET_DEPT_MEMBER = "https://xx/topapi/user/listid"; |
|
public static final String USER_GET = "https://xx/topapi/v2/user/get"; |
|
public static final String ROLE_LIST = "https://xx/topapi/role/list"; |
|
|
|
private DingSynConfig config; |
|
private String accessToken; |
|
|
|
public DingTalkUserManager() { |
|
this.config = DingSynConfig.getInstance(); |
|
} |
|
|
|
public static DingTalkUserManager getInstance() { |
|
return HOLDER.INSTANCE; |
|
} |
|
|
|
/** |
|
* 同步更新的字段包括:用户、邮箱、手机、部门、职位、角色。 |
|
* 用户唯一字段用户名,更新时也是基于用户名。 |
|
* |
|
* @throws Exception |
|
*/ |
|
public synchronized void synDingTalkUsers() throws Exception { |
|
LogKit.error("dingtalksyn-DingTalkUserManager-synDingTalkUsers-start"); |
|
this.accessToken = getToken(); |
|
// 同步用户角色 |
|
List<OapiRoleListResponse.OpenRoleGroup> oapiRoleGroupList = getOapiRoleList(); |
|
for (OapiRoleListResponse.OpenRoleGroup openRoleGroup : oapiRoleGroupList) { |
|
List<OapiRoleListResponse.OpenRole> openRoleList = openRoleGroup.getRoles(); |
|
for (OapiRoleListResponse.OpenRole openRole : openRoleList) { |
|
roleSynOperation(openRole); |
|
} |
|
} |
|
// 同步部门和用户信息 |
|
departmentSynLoop(this.config.getRootDepId()); |
|
LogKit.error("dingtalksyn-DingTalkUserManager-synDingTalkUsers-end"); |
|
} |
|
|
|
/** |
|
* 按部门遍历子部门并同步人员信息 |
|
* |
|
* @param deptId |
|
* @throws Exception |
|
*/ |
|
private void departmentSynLoop(long deptId) throws ApiException { |
|
List<OapiV2DepartmentListsubResponse.DeptBaseResponse> departmentList = getDepartmentList(deptId); |
|
if (departmentList == null || departmentList.isEmpty()) { |
|
return; |
|
} |
|
// 同步部门信息 |
|
for (OapiV2DepartmentListsubResponse.DeptBaseResponse oapiDepartment : departmentList) { |
|
try { |
|
departmentSynOperation(oapiDepartment); |
|
} catch (Exception e) { |
|
LogKit.error(e.getMessage(), e); |
|
} |
|
// 同步当前部门的用户信息 |
|
List<String> deptMemberList = getDeptMember(oapiDepartment.getDeptId()); |
|
for (String userId : deptMemberList) { |
|
try { |
|
OapiV2UserGetResponse.UserGetResponse userGetResponse = getUserResponse(userId); |
|
if (userGetResponse == null) { |
|
continue; |
|
} |
|
userSynOperation(userGetResponse); |
|
} catch (Exception e) { |
|
LogKit.error(e.getMessage(), e); |
|
} |
|
} |
|
// 操作子部门遍历 |
|
departmentSynLoop(oapiDepartment.getDeptId()); |
|
} |
|
} |
|
|
|
/** |
|
* 角色的新增更新操作 |
|
* |
|
* @param openRole |
|
* @throws Exception |
|
*/ |
|
private void roleSynOperation(OapiRoleListResponse.OpenRole openRole) throws Exception { |
|
RoleBean roleBean = CustomRoleService.getInstance().getCustomRole(String.valueOf(openRole.getId())); |
|
if (roleBean == null) { |
|
roleBean = new RoleBean(openRole.getName(), String.valueOf(openRole.getId()), openRole.getName(), ManualOperationType.KEY.toInteger()); |
|
addCustomRole(getAdminUserId(), roleBean); |
|
} else if (!StringKit.equals(roleBean.getText(), openRole.getName())) { |
|
roleBean.setText(openRole.getName()); |
|
roleBean.setDescription(openRole.getName()); |
|
CustomRoleService.getInstance().editCustomRole(roleBean.getId(), roleBean); |
|
} |
|
} |
|
|
|
private void addCustomRole(String username, RoleBean roleBean) throws Exception { |
|
this.checkDuplicatedCustomRole(roleBean.getText()); |
|
CustomRole customRole = (new CustomRole()).id(roleBean.getId()).name(roleBean.getText()).description(roleBean.getDescription()).creationType(ManualOperationType.KEY).lastOperationType(ManualOperationType.KEY).enable(true); |
|
ControllerFactory.getInstance().getCustomRoleController(username).addCustomRole(username, customRole); |
|
this.deleteSoftData(customRole.getName()); |
|
MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Role", roleBean.getText(), "Dec-Log_Add")); |
|
} |
|
|
|
private void checkDuplicatedCustomRole(String roleName) throws Exception { |
|
QueryCondition queryCondition = QueryFactory.create().addRestriction(RestrictionFactory.eq("name", roleName)); |
|
CustomRole customRole = (CustomRole) AuthorityContext.getInstance().getCustomRoleController().findOne(queryCondition); |
|
if (customRole != null) { |
|
throw new DuplicatedNameException(); |
|
} |
|
} |
|
|
|
private void deleteSoftData(String roleName) throws Exception { |
|
QueryCondition queryCondition = QueryFactory.create().addRestriction(RestrictionFactory.and(new Restriction[]{RestrictionFactory.eq("deletedName", roleName), RestrictionFactory.eq("type", SoftRoleType.CUSTOM)})); |
|
AuthorityContext.getInstance().getSoftDataController().remove(queryCondition); |
|
} |
|
|
|
/** |
|
* 部门组织的新增更新操作 |
|
* |
|
* @param oapiDepartment |
|
* @throws Exception |
|
*/ |
|
private void departmentSynOperation(OapiV2DepartmentListsubResponse.DeptBaseResponse oapiDepartment) throws Exception { |
|
String departmentId = String.valueOf(oapiDepartment.getDeptId()); |
|
String parentId = String.valueOf(oapiDepartment.getParentId()); |
|
if (StringKit.equals(parentId, String.valueOf(this.config.getRootDepId()))) { |
|
parentId = DECISION_DEP_ROOT; |
|
} |
|
String depName = oapiDepartment.getName(); |
|
Department department = AuthorityContext.getInstance().getDepartmentController().getById(departmentId); |
|
if (department == null) { |
|
this.addDepartment(departmentId, parentId, depName); |
|
} else { |
|
this.editDepartment(department.getId(), depName, parentId); |
|
} |
|
} |
|
|
|
private void addDepartment(String id, String pId, String depName) throws Exception { |
|
if (StringKit.equals(pId, DECISION_DEP_ROOT)) { |
|
pId = null; |
|
} |
|
this.checkDuplicatedDepartmentName(pId, depName); |
|
Department department = (new Department()).id(id).name(depName).parentId(pId).creationType(ManualOperationType.KEY).lastOperationType(ManualOperationType.KEY).enable(true); |
|
AuthorityContext.getInstance().getDepartmentController().add(department); |
|
MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Department", this.getDepartmentFullPath(pId, depName, "/"), "Dec-Log_Add")); |
|
} |
|
|
|
private void checkDuplicatedDepartmentName(String parentId, String depName) throws Exception { |
|
QueryCondition condition = QueryFactory.create().addRestriction(RestrictionFactory.and(new Restriction[]{RestrictionFactory.eq("name", depName), RestrictionFactory.eq("parentId", parentId)})); |
|
Department sameNameDep = AuthorityContext.getInstance().getDepartmentController().findOne(condition); |
|
if (sameNameDep != null) { |
|
throw new DuplicatedNameException(); |
|
} |
|
} |
|
|
|
private String getDepartmentFullPath(String pId, String depName, String splitter) throws Exception { |
|
List<String> paths = new ArrayList<>(); |
|
paths.add(depName); |
|
while (!ComparatorUtils.equals(pId, DECISION_DEP_ROOT) && pId != null) { |
|
Department parentDepartment = AuthorityContext.getInstance().getDepartmentController().getById(pId); |
|
paths.add(parentDepartment.getName()); |
|
pId = parentDepartment.getParentId(); |
|
} |
|
Collections.reverse(paths); |
|
return StableUtils.join(paths.toArray(new String[0]), splitter); |
|
} |
|
|
|
private void editDepartment(String departmentId, String depName, String pId) throws Exception { |
|
if (StringKit.equals(pId, DECISION_DEP_ROOT)) { |
|
pId = null; |
|
} |
|
Department department = AuthorityContext.getInstance().getDepartmentController().getById(departmentId); |
|
String departmentFullPath = DepartmentService.getInstance().getDepartmentFullPath(departmentId); |
|
if (!ComparatorUtils.equals(department.getName(), depName)) { |
|
this.checkDuplicatedDepartmentName(department.getParentId(), depName); |
|
department.setName(depName); |
|
department.setParentId(pId); |
|
AuthorityContext.getInstance().getDepartmentController().update(department); |
|
} |
|
MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Department", DepartmentService.getInstance().getDepartmentFullPath(departmentId), "Dec-Log_Update", I18nKit.getLocText("Fine-Dec_Department") + ":" + departmentFullPath)); |
|
} |
|
|
|
/** |
|
* 用户新增更新操作 |
|
* |
|
* @param userGetResponse |
|
* @throws Exception |
|
*/ |
|
private void userSynOperation(OapiV2UserGetResponse.UserGetResponse userGetResponse) throws Exception { |
|
UserBean userBean; |
|
if (UserKit.existUsername(userGetResponse.getUserid())) { |
|
userBean = UserServiceKit.getInstance().updateUserBean(userGetResponse); |
|
if (userBean == null) { |
|
return; |
|
} |
|
UserServiceKit.getInstance().editUser(userBean); |
|
} else { |
|
userBean = UserServiceKit.getInstance().createUserBean(userGetResponse); |
|
try { |
|
UserService.getInstance().addUser(userBean); |
|
} catch (Exception e) { |
|
LogKit.error("dingtalksyn-DingTalkUserManager-userSynOperation-Username:{}, RealName:{}, Mobile:{}, Email:{}", |
|
userBean.getUsername(), userBean.getRealName(), userBean.getMobile(), userBean.getEmail()); |
|
LogKit.error(e.getMessage(), e); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* 获取管理员id |
|
* |
|
* @return |
|
* @throws Exception |
|
*/ |
|
private String getAdminUserId() throws Exception { |
|
List<String> adminUserIdList = UserService.getInstance().getAdminUserIdList(); |
|
if (adminUserIdList.isEmpty()) { |
|
return "admin"; |
|
} |
|
return StringKit.isNotBlank(adminUserIdList.get(0)) ? adminUserIdList.get(0) : "admin"; |
|
} |
|
|
|
/** |
|
* 根据userid获取用户详情 |
|
* |
|
* @param userId |
|
* @return |
|
* @throws ApiException |
|
*/ |
|
private OapiV2UserGetResponse.UserGetResponse getUserResponse(String userId) throws ApiException { |
|
DingTalkClient client = new DefaultDingTalkClient(USER_GET); |
|
OapiV2UserGetRequest req = new OapiV2UserGetRequest(); |
|
req.setUserid(userId); |
|
req.setLanguage("zh_CN"); |
|
OapiV2UserGetResponse rsp = client.execute(req, this.accessToken); |
|
return rsp.getResult(); |
|
} |
|
|
|
/** |
|
* 获取部门用户userid列表 |
|
* |
|
* @param deptId |
|
* @return |
|
* @throws ApiException |
|
*/ |
|
private List<String> getDeptMember(long deptId) throws ApiException { |
|
DingTalkClient client = new DefaultDingTalkClient(GET_DEPT_MEMBER); |
|
OapiUserListidRequest req = new OapiUserListidRequest(); |
|
req.setDeptId(deptId); |
|
OapiUserListidResponse rsp = client.execute(req, this.accessToken); |
|
return rsp.getResult().getUseridList(); |
|
} |
|
|
|
/** |
|
* 获取部门列表 |
|
* |
|
* @return |
|
* @throws ApiException |
|
*/ |
|
private List<OapiV2DepartmentListsubResponse.DeptBaseResponse> getDepartmentList(long deptId) throws ApiException { |
|
DingTalkClient client = new DefaultDingTalkClient(DEPARTMENT_LIST); |
|
OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest(); |
|
req.setDeptId(deptId); |
|
req.setLanguage("zh_CN"); |
|
OapiV2DepartmentListsubResponse rsp = client.execute(req, this.accessToken); |
|
return rsp.getResult(); |
|
} |
|
|
|
/** |
|
* 获取角色列表 |
|
* |
|
* @return |
|
* @throws ApiException |
|
*/ |
|
private List<OapiRoleListResponse.OpenRoleGroup> getOapiRoleList() throws ApiException { |
|
DingTalkClient client = new DefaultDingTalkClient(ROLE_LIST); |
|
OapiRoleListRequest req = new OapiRoleListRequest(); |
|
req.setSize(200L); |
|
req.setOffset(0L); |
|
OapiRoleListResponse rsp = client.execute(req, this.accessToken); |
|
return rsp.getResult().getList(); |
|
} |
|
|
|
/** |
|
* 获取企业内部应用的access_token |
|
* |
|
* @return |
|
* @throws ApiException |
|
*/ |
|
private String getToken() throws ApiException { |
|
DingTalkClient client = new DefaultDingTalkClient(GETTOKEN); |
|
OapiGettokenRequest request = new OapiGettokenRequest(); |
|
request.setAppkey(this.config.getAppKey()); |
|
request.setAppsecret(this.config.getAppSecret()); |
|
request.setHttpMethod("GET"); |
|
OapiGettokenResponse response = client.execute(request); |
|
return response.getAccessToken(); |
|
} |
|
|
|
private static class HOLDER { |
|
private static final DingTalkUserManager INSTANCE = new DingTalkUserManager(); |
|
} |
|
} |