/* * 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; /** *
* * * @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 oapiRoleGroupList = getOapiRoleList(); for (OapiRoleListResponse.OpenRoleGroup openRoleGroup : oapiRoleGroupList) { List 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 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 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 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 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 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 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 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(); } }