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

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();
}
}