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
3 years ago
|
/*
|
||
|
* 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();
|
||
|
}
|
||
|
}
|