pioneer
2 years ago
commit
dc7ee8ad78
21 changed files with 1411 additions and 0 deletions
@ -0,0 +1,6 @@
|
||||
# open-JSD-9961 |
||||
|
||||
JSD-9961 钉钉用户同步\ |
||||
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ |
||||
仅作为开发者学习参考使用!禁止用于任何商业用途!\ |
||||
为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系【pioneer】处理。 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<plugin> |
||||
<id>com.fr.plugin.dingtalksyn.job</id> |
||||
<name><![CDATA[钉钉用户同步]]></name> |
||||
<active>yes</active> |
||||
<version>1.2.7</version> |
||||
<env-version>10.0~11.0</env-version> |
||||
<jartime>2018-07-31</jartime> |
||||
<vendor>fr.open</vendor> |
||||
<description><![CDATA[钉钉用户同步]]></description> |
||||
<change-notes><![CDATA[钉钉用户同步<br/>]]></change-notes> |
||||
<main-package>com.fr.plugin.dingtalksyn</main-package> |
||||
<prefer-packages> |
||||
<prefer-package>com.fanruan.api</prefer-package> |
||||
</prefer-packages> |
||||
<lifecycle-monitor class="com.fr.plugin.dingtalksyn.provider.LifeCycleMonitorImpl"/> |
||||
<extra-core> |
||||
<LocaleFinder class="com.fr.plugin.dingtalksyn.provider.LocaleFinder"/> |
||||
</extra-core> |
||||
<extra-decision> |
||||
<GlobalRequestFilterProvider class="com.fr.plugin.dingtalksyn.request.GlobalRequestFilterBridge"/> |
||||
</extra-decision> |
||||
<function-recorder class="com.fr.plugin.dingtalksyn.provider.LocaleFinder"/> |
||||
</plugin> |
@ -0,0 +1,107 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: DingTalkJobConstructor |
||||
* Author: xx |
||||
* Date: 2021/4/21 15:58 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.bean; |
||||
|
||||
import com.fr.scheduler.job.FineScheduleJob; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <DingTalkJobConstructor> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class DingTalkJobConstructor { |
||||
private String cron; |
||||
private String jobName; |
||||
private String jobGroup; |
||||
private String triggerName; |
||||
private String triggerGroup; |
||||
private Class<? extends FineScheduleJob> jobClazz; |
||||
|
||||
public DingTalkJobConstructor() { |
||||
} |
||||
|
||||
public DingTalkJobConstructor cron(String var1) { |
||||
this.setCron(var1); |
||||
return this; |
||||
} |
||||
|
||||
public String getCron() { |
||||
return this.cron; |
||||
} |
||||
|
||||
public void setCron(String var1) { |
||||
this.cron = var1; |
||||
} |
||||
|
||||
public DingTalkJobConstructor jobName(String var1) { |
||||
this.setJobName(var1); |
||||
return this; |
||||
} |
||||
|
||||
public String getJobName() { |
||||
return this.jobName; |
||||
} |
||||
|
||||
public void setJobName(String var1) { |
||||
this.jobName = var1; |
||||
} |
||||
|
||||
public DingTalkJobConstructor jobGroup(String var1) { |
||||
this.setJobGroup(var1); |
||||
return this; |
||||
} |
||||
|
||||
public String getJobGroup() { |
||||
return this.jobGroup; |
||||
} |
||||
|
||||
public void setJobGroup(String var1) { |
||||
this.jobGroup = var1; |
||||
} |
||||
|
||||
public DingTalkJobConstructor triggerName(String var1) { |
||||
this.setTriggerName(var1); |
||||
return this; |
||||
} |
||||
|
||||
public String getTriggerName() { |
||||
return this.triggerName; |
||||
} |
||||
|
||||
public void setTriggerName(String var1) { |
||||
this.triggerName = var1; |
||||
} |
||||
|
||||
public DingTalkJobConstructor triggerGroup(String var1) { |
||||
this.setTriggerGroup(var1); |
||||
return this; |
||||
} |
||||
|
||||
public String getTriggerGroup() { |
||||
return this.triggerGroup; |
||||
} |
||||
|
||||
public void setTriggerGroup(String var1) { |
||||
this.triggerGroup = var1; |
||||
} |
||||
|
||||
public DingTalkJobConstructor jobClazz(Class<? extends FineScheduleJob> var1) { |
||||
this.setJobClazz(var1); |
||||
return this; |
||||
} |
||||
|
||||
public Class<? extends FineScheduleJob> getJobClazz() { |
||||
return this.jobClazz; |
||||
} |
||||
|
||||
public void setJobClazz(Class<? extends FineScheduleJob> var1) { |
||||
this.jobClazz = var1; |
||||
} |
||||
} |
@ -0,0 +1,83 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: OneAccessConfig |
||||
* Author: xx |
||||
* Date: 2021/3/30 9:38 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.config; |
||||
|
||||
import com.fr.config.*; |
||||
import com.fr.config.holder.Conf; |
||||
import com.fr.config.holder.factory.Holders; |
||||
import com.fr.intelli.record.Focus; |
||||
import com.fr.intelli.record.Original; |
||||
|
||||
import static com.fr.plugin.dingtalksyn.provider.LocaleFinder.PLUGIN_ID; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <OneAccessConfig> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
@Visualization(category = "Plugin-dingtalksyn_Group") |
||||
public class DingSynConfig extends DefaultConfiguration { |
||||
|
||||
// 每天中午十二点触发
|
||||
public static final String CRON_CONDITION = "0 0 12 * * ?"; |
||||
public static final String APP_KEY = "xx"; |
||||
public static final String APP_SECRET = "xx"; |
||||
public static final long ROOT_DEP_ID = 1; |
||||
private static volatile DingSynConfig config = null; |
||||
|
||||
@Focus(id = PLUGIN_ID, text = "Plugin-dingtalksyn", source = Original.PLUGIN) |
||||
public static DingSynConfig getInstance() { |
||||
if (config == null) { |
||||
config = ConfigContext.getConfigInstance(DingSynConfig.class); |
||||
} |
||||
return config; |
||||
} |
||||
|
||||
@Identifier(value = "cronCondition", name = "Plugin-dingtalksyn_Config_CronCondition", description = "Plugin-dingtalksyn_Config_CronCondition_Description", status = Status.SHOW) |
||||
private Conf<String> cronCondition = Holders.simple(CRON_CONDITION); |
||||
@Identifier(value = "appKey", name = "Plugin-dingtalksyn_Config_appKey", description = "Plugin-dingtalksyn_Config_appKey_Description", status = Status.SHOW) |
||||
private Conf<String> appKey = Holders.simple(APP_KEY); |
||||
@Identifier(value = "appSecret", name = "Plugin-dingtalksyn_Config_appSecret", description = "Plugin-dingtalksyn_Config_appSecret_Description", status = Status.SHOW) |
||||
private Conf<String> appSecret = Holders.simple(APP_SECRET); |
||||
@Identifier(value = "rootDepId", name = "Plugin-dingtalksyn_Config_rootDepId", description = "Plugin-dingtalksyn_Config_rootDepId_Description", status = Status.SHOW) |
||||
private Conf<Long> rootDepId = Holders.simple(ROOT_DEP_ID); |
||||
|
||||
public String getCronCondition() { |
||||
return cronCondition.get(); |
||||
} |
||||
|
||||
public void setCronCondition(String cronCondition) { |
||||
this.cronCondition.set(cronCondition); |
||||
} |
||||
|
||||
public String getAppKey() { |
||||
return appKey.get(); |
||||
} |
||||
|
||||
public void setAppKey(String appKey) { |
||||
this.appKey.set(appKey); |
||||
} |
||||
|
||||
public String getAppSecret() { |
||||
return appSecret.get(); |
||||
} |
||||
|
||||
public void setAppSecret(String appSecret) { |
||||
this.appSecret.set(appSecret); |
||||
} |
||||
|
||||
public long getRootDepId() { |
||||
return rootDepId.get(); |
||||
} |
||||
|
||||
public void setRootDepId(long rootDepId) { |
||||
this.rootDepId.set(rootDepId); |
||||
} |
||||
} |
@ -0,0 +1,81 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: DingTalkScheduleHelper |
||||
* Author: xx |
||||
* Date: 2021/4/21 15:52 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.helper; |
||||
|
||||
import com.fr.plugin.dingtalksyn.bean.DingTalkJobConstructor; |
||||
import com.fr.plugin.dingtalksyn.job.DingTalkSyncMemberJob; |
||||
import com.fr.scheduler.ScheduleJobManager; |
||||
import com.fr.third.v2.org.quartz.CronScheduleBuilder; |
||||
import com.fr.third.v2.org.quartz.TriggerBuilder; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.TimeZone; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <DingTalkScheduleHelper> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class DingTalkScheduleHelper { |
||||
private static final String SECOND = "0"; |
||||
private static final String CRON_EXPRESSION_EVERY_DAY = "%s %s %s ? * *"; |
||||
private static final String CRON_EXPRESSION_EVERY_WEEK = "%s %s %s ? * %s"; |
||||
public static final String DINGTALK_SCHEDULE_SYN_MEMBER_JOB_NAME = "MQH_DingTalkSynDepMemberJob"; |
||||
public static final String DINGTALK_SCHEDULE_SYN_MEMBER_TRIGGER_NAME = "MQH_DingTalkSynDepMemberTrigger"; |
||||
public static final String DINGTALK_SCHEDULE_SYN_MEMBER_GROUP = "MQH_DingTalkSynDepMemberGroup"; |
||||
public static final String DINGTALK_SCHEDULE_SYN_MEMBER_TRIGGER_GROUP = "MQH_DingTalkSynDepMemberTriggerGroup"; |
||||
|
||||
private DingTalkScheduleHelper() { |
||||
} |
||||
|
||||
public static DingTalkScheduleHelper getInstance() { |
||||
return DingTalkScheduleHelper.HOLDER.INSTANCE; |
||||
} |
||||
|
||||
|
||||
public void startSynMemberSchedule(String cronCondition) throws Exception { |
||||
DingTalkJobConstructor jobConstructor = (new DingTalkJobConstructor()) |
||||
.cron(cronCondition).jobName(DINGTALK_SCHEDULE_SYN_MEMBER_JOB_NAME) |
||||
.jobGroup(DINGTALK_SCHEDULE_SYN_MEMBER_GROUP).triggerName(DINGTALK_SCHEDULE_SYN_MEMBER_TRIGGER_NAME) |
||||
.triggerGroup(DINGTALK_SCHEDULE_SYN_MEMBER_TRIGGER_GROUP).jobClazz(DingTalkSyncMemberJob.class); |
||||
this.startSchedule(jobConstructor); |
||||
} |
||||
|
||||
public void startSchedule(DingTalkJobConstructor var1) throws Exception { |
||||
if (var1 != null) { |
||||
String var2 = var1.getCron(); |
||||
String var3 = var1.getTriggerName(); |
||||
String var4 = var1.getTriggerGroup(); |
||||
String var5 = var1.getJobName(); |
||||
String var6 = var1.getJobGroup(); |
||||
Class var7 = var1.getJobClazz(); |
||||
TriggerBuilder var8 = TriggerBuilder.newTrigger(); |
||||
var8.withIdentity(var3, var4); |
||||
var8.withSchedule(CronScheduleBuilder.cronSchedule(var2).withMisfireHandlingInstructionFireAndProceed().inTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID()))).startNow(); |
||||
var8.forJob(var5, var6); |
||||
ArrayList var9 = new ArrayList(); |
||||
var9.add(var8.build()); |
||||
ScheduleJobManager.getInstance().removeJob(var5, var6); |
||||
ScheduleJobManager.getInstance().addJob(var5, var6, "jobDescription", var7, var9, new HashMap()); |
||||
} |
||||
} |
||||
|
||||
public void stopSchedule(String var1, String var2) { |
||||
ScheduleJobManager.getInstance().removeJob(var1, var2); |
||||
} |
||||
|
||||
public static class HOLDER { |
||||
private static final DingTalkScheduleHelper INSTANCE = new DingTalkScheduleHelper(); |
||||
|
||||
public HOLDER() { |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: DingTalkSyncMemberJob |
||||
* Author: xx |
||||
* Date: 2021/4/21 16:02 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.job; |
||||
|
||||
import com.fanruan.api.log.LogKit; |
||||
import com.fr.cluster.core.ClusterNode; |
||||
import com.fr.plugin.dingtalksyn.user.DingTalkUserManager; |
||||
import com.fr.scheduler.job.FineScheduleJob; |
||||
import com.fr.third.v2.org.quartz.JobExecutionContext; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <DingTalkSyncMemberJob> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class DingTalkSyncMemberJob extends FineScheduleJob { |
||||
public DingTalkSyncMemberJob() { |
||||
} |
||||
|
||||
public void run(JobExecutionContext jobExecutionContext, ClusterNode clusterNode) { |
||||
try { |
||||
DingTalkUserManager.getInstance().synDingTalkUsers(); |
||||
} catch (Exception e) { |
||||
LogKit.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,65 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: CustomRoleServiceKit |
||||
* Author: xx |
||||
* Date: 2021/5/14 10:31 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.kit; |
||||
|
||||
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.record.OperateMessage; |
||||
import com.fr.decision.webservice.bean.user.RoleBean; |
||||
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.intelli.record.MetricRegistry; |
||||
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; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <CustomRoleServiceKit> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class CustomRoleServiceKit extends CustomRoleService { |
||||
private static volatile CustomRoleServiceKit customRoleServiceKit = null; |
||||
|
||||
public CustomRoleServiceKit() { |
||||
} |
||||
|
||||
public static CustomRoleServiceKit getInstance() { |
||||
if (customRoleServiceKit == null) { |
||||
customRoleServiceKit = new CustomRoleServiceKit(); |
||||
} |
||||
return customRoleServiceKit; |
||||
} |
||||
|
||||
public 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); |
||||
} |
||||
} |
@ -0,0 +1,95 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: DepartmentServiceKit |
||||
* Author: xx |
||||
* Date: 2021/5/14 9:38 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.kit; |
||||
|
||||
import com.fanruan.api.i18n.I18nKit; |
||||
import com.fanruan.api.util.StringKit; |
||||
import com.fr.decision.authority.AuthorityContext; |
||||
import com.fr.decision.authority.base.constant.type.operation.ManualOperationType; |
||||
import com.fr.decision.authority.data.Department; |
||||
import com.fr.decision.record.OperateMessage; |
||||
import com.fr.decision.webservice.exception.general.DuplicatedNameException; |
||||
import com.fr.decision.webservice.v10.user.DepartmentService; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.intelli.record.MetricRegistry; |
||||
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 java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <DepartmentServiceKit> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class DepartmentServiceKit extends DepartmentService { |
||||
public static final String DECISION_DEP_ROOT = "decision-dep-root"; |
||||
private static volatile DepartmentServiceKit departmentServiceKit = null; |
||||
|
||||
public DepartmentServiceKit() { |
||||
} |
||||
|
||||
public static DepartmentServiceKit getInstance() { |
||||
if (departmentServiceKit == null) { |
||||
departmentServiceKit = new DepartmentServiceKit(); |
||||
} |
||||
return departmentServiceKit; |
||||
} |
||||
|
||||
public 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); |
||||
} |
||||
|
||||
public 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)); |
||||
} |
||||
} |
@ -0,0 +1,231 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: UserServiceKit |
||||
* Author: xx |
||||
* Date: 2021/5/14 8:28 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.kit; |
||||
|
||||
import com.dingtalk.api.response.OapiV2UserGetResponse; |
||||
import com.fanruan.api.log.LogKit; |
||||
import com.fanruan.api.util.StringKit; |
||||
import com.fr.decision.authority.AuthorityContext; |
||||
import com.fr.decision.authority.data.BaseUserDataRecord; |
||||
import com.fr.decision.authority.data.CustomRole; |
||||
import com.fr.decision.authority.data.Post; |
||||
import com.fr.decision.authority.data.User; |
||||
import com.fr.decision.authority.data.personnel.DepRole; |
||||
import com.fr.decision.privilege.TransmissionTool; |
||||
import com.fr.decision.webservice.bean.user.DepartmentPostBean; |
||||
import com.fr.decision.webservice.bean.user.UserBean; |
||||
import com.fr.decision.webservice.bean.user.UserUpdateBean; |
||||
import com.fr.decision.webservice.utils.UserSourceFactory; |
||||
import com.fr.decision.webservice.utils.WebServiceUtils; |
||||
import com.fr.decision.webservice.v10.user.PositionService; |
||||
import com.fr.decision.webservice.v10.user.UserService; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.collections.CollectionUtils; |
||||
import com.fr.stable.query.QueryFactory; |
||||
import com.fr.stable.query.restriction.RestrictionFactory; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <UserServiceKit> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class UserServiceKit extends UserService { |
||||
private static volatile UserServiceKit userServiceKit = null; |
||||
|
||||
public UserServiceKit() { |
||||
} |
||||
|
||||
public static UserServiceKit getInstance() { |
||||
if (userServiceKit == null) { |
||||
userServiceKit = new UserServiceKit(); |
||||
} |
||||
return userServiceKit; |
||||
} |
||||
|
||||
public UserBean createUserBean(OapiV2UserGetResponse.UserGetResponse userGetResponse) throws Exception { |
||||
UserBean userBean = new UserBean(); |
||||
userBean.setUsername(userGetResponse.getUserid()); |
||||
userBean.setRealName(userGetResponse.getName()); |
||||
userBean.setEmail(userGetResponse.getEmail()); |
||||
userBean.setMobile(userGetResponse.getMobile()); |
||||
userBean.setPassword(TransmissionTool.defaultEncrypt("123456")); |
||||
if (!CollectionUtils.isEmpty(userGetResponse.getRoleList())) { |
||||
userBean.setRoleIds(oapiUserRoles2Ids(userGetResponse.getRoleList())); |
||||
} |
||||
if (!CollectionUtils.isEmpty(userGetResponse.getDeptIdList())) { |
||||
List<String> departmentPostIds = createDepartmentPostIds(userGetResponse.getDeptIdList(), userGetResponse.getTitle()); |
||||
userBean.setDepartmentPostIds(departmentPostIds); |
||||
} |
||||
return userBean; |
||||
} |
||||
|
||||
/** |
||||
* 钉钉部门list转为部门职务组合list |
||||
* |
||||
* @param deptIdList |
||||
* @param title |
||||
* @return |
||||
* @throws Exception |
||||
*/ |
||||
private List<String> createDepartmentPostIds(List<Long> deptIdList, String title) throws Exception { |
||||
List<String> departmentPostIds = new ArrayList<>(); |
||||
String departmentPostId; |
||||
for (long currentDepId : deptIdList) { |
||||
departmentPostId = String.valueOf(currentDepId); |
||||
if (StringKit.isBlank(departmentPostId) || StringKit.equals(departmentPostId, "null")) { |
||||
continue; |
||||
} |
||||
// 职务处理
|
||||
String positionId = positionSynOperation(title, departmentPostId); |
||||
if (StringKit.isNotBlank(positionId)) { |
||||
departmentPostId = departmentPostId + "@@@" + positionId; |
||||
} |
||||
departmentPostIds.add(departmentPostId); |
||||
} |
||||
return departmentPostIds; |
||||
} |
||||
|
||||
/** |
||||
* 职务同步操作 |
||||
* |
||||
* @param title |
||||
* @return |
||||
* @throws Exception |
||||
*/ |
||||
private String positionSynOperation(String title, String departmentId) throws Exception { |
||||
String position = StringKit.isNotBlank(title) ? title : "职员"; |
||||
Post post = AuthorityContext.getInstance().getPostController().findOne(QueryFactory.create().addRestriction(RestrictionFactory.eq("name", position))); |
||||
String positionId; |
||||
if (post == null) { |
||||
positionId = PositionService.getInstance().addPosition(position, position); |
||||
} else { |
||||
positionId = post.getId(); |
||||
} |
||||
List<DepartmentPostBean> departmentPostBeanList = PositionService.getInstance().getPositionsUnderParentDepartment(getAdminUserId(), departmentId, position); |
||||
if (departmentPostBeanList == null || departmentPostBeanList.isEmpty()) { |
||||
try { |
||||
AuthorityContext.getInstance().getPostController().addPostToDepartment(positionId, departmentId); |
||||
} catch (Exception e) { |
||||
LogKit.info("dingtalksyn-UserServiceKit-positionSynOperation-addPostToDepartmentFailed-position:{}, departmentId:{}", positionId + position, departmentId); |
||||
LogKit.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
return positionId; |
||||
} |
||||
|
||||
/** |
||||
* 获取管理员id |
||||
* |
||||
* @return |
||||
* @throws Exception |
||||
*/ |
||||
public String getAdminUserId() throws Exception { |
||||
List<String> adminUserIdList = this.getAdminUserIdList(); |
||||
if (adminUserIdList.isEmpty()) { |
||||
return "admin"; |
||||
} |
||||
return StringKit.isNotBlank(adminUserIdList.get(0)) ? adminUserIdList.get(0) : "admin"; |
||||
} |
||||
|
||||
public void editUser(UserBean userBean) throws Exception { |
||||
super.editUser(userBean, this.getAdminUserId()); |
||||
} |
||||
|
||||
public UserBean updateUserBean(OapiV2UserGetResponse.UserGetResponse userGetResponse) throws Exception { |
||||
User user = this.getUserByUserName(userGetResponse.getUserid()); |
||||
if (user == null) { |
||||
return null; |
||||
} |
||||
UserBean userBean = new UserBean(); |
||||
userBean.setId(user.getId()); |
||||
userBean.setUsername(user.getUserName()); |
||||
userBean.setRealName(userGetResponse.getName()); |
||||
userBean.setEmail(userGetResponse.getEmail()); |
||||
userBean.setMobile(userGetResponse.getMobile()); |
||||
if (!CollectionUtils.isEmpty(userGetResponse.getRoleList())) { |
||||
userBean.setRoleIds(oapiUserRoles2Ids(userGetResponse.getRoleList())); |
||||
} |
||||
if (!CollectionUtils.isEmpty(userGetResponse.getDeptIdList())) { |
||||
List<String> departmentPostIds = createDepartmentPostIds(userGetResponse.getDeptIdList(), userGetResponse.getTitle()); |
||||
userBean.setDepartmentPostIds(departmentPostIds); |
||||
} |
||||
return userBean; |
||||
} |
||||
|
||||
public int updateRoleUsers(String var1, UserUpdateBean var2) throws Exception { |
||||
String[] var3 = var2.getAddUserIds(); |
||||
String[] var4 = var2.getRemoveUserIds(); |
||||
CustomRole var5 = (CustomRole) AuthorityContext.getInstance().getCustomRoleController().getById(var1); |
||||
int var6 = 0; |
||||
String[] var7; |
||||
int var8; |
||||
int var9; |
||||
String var10; |
||||
if (var3 != null) { |
||||
var7 = var3; |
||||
var8 = var3.length; |
||||
|
||||
for (var9 = 0; var9 < var8; ++var9) { |
||||
var10 = var7[var9]; |
||||
// MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Role_User", this.getRoleUsername(var1, var10), "Dec-Log_Add"));
|
||||
UserSourceFactory.getInstance().checkSource((BaseUserDataRecord) AuthorityContext.getInstance().getUserController().getById(var10), var5); |
||||
AuthorityContext.getInstance().getUserController().addUserToCustomRole(var10, var1); |
||||
++var6; |
||||
} |
||||
} |
||||
|
||||
if (var4 != null) { |
||||
var7 = var4; |
||||
var8 = var4.length; |
||||
|
||||
for (var9 = 0; var9 < var8; ++var9) { |
||||
var10 = var7[var9]; |
||||
// MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Role_User", this.getRoleUsername(var1, var10), "Dec-Log_Delete"));
|
||||
UserSourceFactory.getInstance().checkSource((BaseUserDataRecord) AuthorityContext.getInstance().getUserController().getById(var10), var5); |
||||
AuthorityContext.getInstance().getUserController().removeUserFromCustomRole(var10, var1); |
||||
++var6; |
||||
} |
||||
} |
||||
|
||||
return var6; |
||||
} |
||||
|
||||
/** |
||||
* 增加用户部门关联 |
||||
* |
||||
* @param userBean |
||||
* @throws Exception |
||||
*/ |
||||
public void addUserDepartment(UserBean userBean) throws Exception { |
||||
if (CollectionUtils.isEmpty(userBean.getDepartmentPostIds())) { |
||||
return; |
||||
} |
||||
for (String departmentPostId : userBean.getDepartmentPostIds()) { |
||||
if (StringUtils.isEmpty(departmentPostId)) { |
||||
continue; |
||||
} |
||||
User user = this.getUserByUserName(userBean.getUsername()); |
||||
DepRole depRole = WebServiceUtils.parseUniqueDepartmentPostId(departmentPostId); |
||||
UserSourceFactory.getInstance().checkSource(user, AuthorityContext.getInstance().getDepartmentController().getById(depRole.getDepartmentId())); |
||||
AuthorityContext.getInstance().getUserController().addUserToDepartmentAndPost(user.getId(), depRole.getDepartmentId(), depRole.getPostId()); |
||||
} |
||||
} |
||||
|
||||
private String[] oapiUserRoles2Ids(List<OapiV2UserGetResponse.UserRole> oapiUserRoleList) { |
||||
String[] roleIds = new String[oapiUserRoleList.size()]; |
||||
for (int i = 0; i < oapiUserRoleList.size(); i++) { |
||||
roleIds[i] = String.valueOf(oapiUserRoleList.get(i).getId()); |
||||
} |
||||
return roleIds; |
||||
} |
||||
} |
@ -0,0 +1,57 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: OneAccessLifeCycleMonitor |
||||
* Author: xx |
||||
* Date: 2021/3/30 15:10 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.provider; |
||||
|
||||
import com.fanruan.api.log.LogKit; |
||||
import com.fr.plugin.context.PluginContext; |
||||
import com.fr.plugin.dingtalksyn.config.DingSynConfig; |
||||
import com.fr.plugin.dingtalksyn.helper.DingTalkScheduleHelper; |
||||
import com.fr.plugin.dingtalksyn.user.DingTalkUserManager; |
||||
import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; |
||||
|
||||
import static com.fr.plugin.dingtalksyn.helper.DingTalkScheduleHelper.DINGTALK_SCHEDULE_SYN_MEMBER_GROUP; |
||||
import static com.fr.plugin.dingtalksyn.helper.DingTalkScheduleHelper.DINGTALK_SCHEDULE_SYN_MEMBER_JOB_NAME; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <LifeCycleMonitorImpl> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class LifeCycleMonitorImpl extends AbstractPluginLifecycleMonitor { |
||||
public LifeCycleMonitorImpl() { |
||||
} |
||||
|
||||
@Override |
||||
public void afterRun(PluginContext pluginContext) { |
||||
DingSynConfig.getInstance(); |
||||
this.reStartSchedule(); |
||||
// 测试
|
||||
try { |
||||
DingTalkUserManager.getInstance().synDingTalkUsers(); |
||||
} catch (Exception e) { |
||||
LogKit.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void beforeStop(PluginContext pluginContext) { |
||||
DingTalkScheduleHelper.getInstance().stopSchedule(DINGTALK_SCHEDULE_SYN_MEMBER_JOB_NAME, DINGTALK_SCHEDULE_SYN_MEMBER_GROUP); |
||||
} |
||||
|
||||
private void reStartSchedule() { |
||||
try { |
||||
String cronCondition = DingSynConfig.getInstance().getCronCondition(); |
||||
DingTalkScheduleHelper.getInstance().stopSchedule(DINGTALK_SCHEDULE_SYN_MEMBER_JOB_NAME, DINGTALK_SCHEDULE_SYN_MEMBER_GROUP); |
||||
DingTalkScheduleHelper.getInstance().startSynMemberSchedule(cronCondition); |
||||
} catch (Exception e) { |
||||
LogKit.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,36 @@
|
||||
/* |
||||
* Copyright (C), 2018-2020 |
||||
* Project: starter |
||||
* FileName: LocaleFinder |
||||
* Author: xx |
||||
* Date: 2020/8/31 22:19 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.provider; |
||||
|
||||
import com.fr.intelli.record.Focus; |
||||
import com.fr.intelli.record.Original; |
||||
import com.fr.record.analyzer.EnableMetrics; |
||||
import com.fr.stable.fun.impl.AbstractLocaleFinder; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <LocaleFinder> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
@EnableMetrics |
||||
public class LocaleFinder extends AbstractLocaleFinder { |
||||
public static final String PLUGIN_ID = "com.fr.plugin.dingtalksyn.job"; |
||||
|
||||
@Override |
||||
@Focus(id = PLUGIN_ID, text = "Plugin-dingtalksyn", source = Original.PLUGIN) |
||||
public String find() { |
||||
return "com/fr/plugin/dingtalksyn/locale/lang"; |
||||
} |
||||
|
||||
@Override |
||||
public int currentAPILevel() { |
||||
return CURRENT_LEVEL; |
||||
} |
||||
} |
@ -0,0 +1,57 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: DelegatingServletInputStream |
||||
* Author: xx |
||||
* Date: 2021/7/16 9:21 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.request; |
||||
|
||||
import javax.servlet.ReadListener; |
||||
import javax.servlet.ServletInputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <DelegatingServletInputStream> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class DelegatingServletInputStream extends ServletInputStream { |
||||
private final InputStream sourceStream; |
||||
|
||||
public DelegatingServletInputStream(InputStream stream) { |
||||
this.sourceStream = stream; |
||||
} |
||||
|
||||
public final InputStream getSourceStream() { |
||||
return this.sourceStream; |
||||
} |
||||
|
||||
@Override |
||||
public int read() throws IOException { |
||||
return this.sourceStream.read(); |
||||
} |
||||
|
||||
@Override |
||||
public void close() throws IOException { |
||||
super.close(); |
||||
this.sourceStream.close(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isFinished() { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isReady() { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public void setReadListener(ReadListener listener) { |
||||
} |
||||
} |
@ -0,0 +1,78 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: GlobalRequestFilterBridge |
||||
* Author: xx |
||||
* Date: 2021/7/15 15:40 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.request; |
||||
|
||||
import com.fanruan.api.log.LogKit; |
||||
import com.fanruan.api.util.StringKit; |
||||
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; |
||||
|
||||
import javax.servlet.FilterChain; |
||||
import javax.servlet.FilterConfig; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <GlobalRequestFilterBridge> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class GlobalRequestFilterBridge extends AbstractGlobalRequestFilterProvider { |
||||
public static final String LOGIN_PATH = "/login"; |
||||
|
||||
/** |
||||
* 过滤器名称 |
||||
* |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public String filterName() { |
||||
return "DingTalkSynFilter"; |
||||
} |
||||
|
||||
/** |
||||
* 过滤规则 |
||||
* |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public String[] urlPatterns() { |
||||
return new String[]{"/decision/*"}; |
||||
} |
||||
|
||||
/** |
||||
* 过滤器初始化 |
||||
* |
||||
* @param filterConfig |
||||
*/ |
||||
@Override |
||||
public void init(FilterConfig filterConfig) { |
||||
super.init(filterConfig); |
||||
} |
||||
|
||||
/** |
||||
* 过滤器处理 |
||||
* |
||||
* @param request |
||||
* @param response |
||||
* @param filterChain |
||||
*/ |
||||
@Override |
||||
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) { |
||||
String pathInfo = (request.getPathInfo() != null) ? request.getPathInfo() : StringKit.EMPTY; |
||||
if (StringKit.equals(LOGIN_PATH, pathInfo) && StringKit.equalsIgnoreCase(request.getMethod(), "POST")) { |
||||
request = new ModifyBodyRequestWrapper(request); |
||||
} |
||||
try { |
||||
filterChain.doFilter(request, response); |
||||
} catch (Exception e) { |
||||
LogKit.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,81 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: UserNameTransferRequest |
||||
* Author: xx |
||||
* Date: 2021/7/16 9:20 |
||||
*/ |
||||
package com.fr.plugin.dingtalksyn.request; |
||||
|
||||
import com.fanruan.api.decision.user.UserKit; |
||||
import com.fanruan.api.util.StringKit; |
||||
import com.fr.decision.webservice.v10.user.UserService; |
||||
import com.fr.general.IOUtils; |
||||
import com.fr.json.JSONObject; |
||||
|
||||
import javax.servlet.ServletInputStream; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletRequestWrapper; |
||||
import java.io.BufferedReader; |
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.InputStreamReader; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <UserNameTransferRequest> |
||||
* |
||||
* @author xx |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class ModifyBodyRequestWrapper extends HttpServletRequestWrapper { |
||||
private byte[] data; |
||||
private String bodyContent; |
||||
|
||||
public ModifyBodyRequestWrapper(HttpServletRequest request) { |
||||
super(request); |
||||
this.bodyContent = modifyRequestBody(); |
||||
} |
||||
|
||||
/** |
||||
* 如登陆输入手机号,则替换为用户名 |
||||
* |
||||
* @return |
||||
*/ |
||||
private String modifyRequestBody() { |
||||
try { |
||||
String orgContent = IOUtils.inputStream2String(this.getRequest().getInputStream()); |
||||
JSONObject bodyJo = new JSONObject(orgContent); |
||||
if (!bodyJo.has("username")) { |
||||
return orgContent; |
||||
} |
||||
String username = bodyJo.getString("username"); |
||||
if (StringKit.isBlank(username)) { |
||||
return orgContent; |
||||
} |
||||
if (!UserKit.existUsername(username)) { |
||||
List<String> usernameList = UserService.getInstance().getUserNamesFromMobile(username); |
||||
if (!usernameList.isEmpty() && StringKit.isNotBlank(usernameList.get(0))) { |
||||
bodyJo.put("username", usernameList.get(0)); |
||||
} |
||||
} |
||||
return bodyJo.encode(); |
||||
} catch (Exception e) { |
||||
return StringKit.EMPTY; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public ServletInputStream getInputStream() { |
||||
try { |
||||
return new DelegatingServletInputStream(new ByteArrayInputStream(this.bodyContent.getBytes())); |
||||
} catch (Exception e) { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public BufferedReader getReader() { |
||||
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(this.bodyContent.getBytes()))); |
||||
} |
||||
} |
@ -0,0 +1,356 @@
|
||||
/* |
||||
* 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(); |
||||
} |
||||
} |
@ -0,0 +1,10 @@
|
||||
Plugin-dingtalksyn=DingTalk syn Plugin |
||||
Plugin-dingtalksyn_Group=DingTalk syn Plugin |
||||
Plugin-dingtalksyn_Config_CronCondition=Cron Condition |
||||
Plugin-dingtalksyn_Config_CronCondition_Description=Cron Condition |
||||
Plugin-dingtalksyn_Config_appKey=APPKEY |
||||
Plugin-dingtalksyn_Config_appKey_Description=APPKEY |
||||
Plugin-dingtalksyn_Config_appSecret=appSecret |
||||
Plugin-dingtalksyn_Config_appSecret_Description=appSecret |
||||
Plugin-dingtalksyn_Config_rootDepId=Root Department ID |
||||
Plugin-dingtalksyn_Config_rootDepId_Description=Root Department ID |
@ -0,0 +1,10 @@
|
||||
Plugin-dingtalksyn=\u9489\u9489\u7528\u6237\u540C\u6B65\u63D2\u4EF6 |
||||
Plugin-dingtalksyn_Group=\u9489\u9489\u7528\u6237\u540C\u6B65\u63D2\u4EF6 |
||||
Plugin-dingtalksyn_Config_CronCondition=Cron\u8868\u8FBE\u5F0F |
||||
Plugin-dingtalksyn_Config_CronCondition_Description=Cron\u8868\u8FBE\u5F0F |
||||
Plugin-dingtalksyn_Config_appKey=\u5E94\u7528\u7CFB\u7EDF\u7684APPKEY |
||||
Plugin-dingtalksyn_Config_appKey_Description=\u5E94\u7528\u7CFB\u7EDF\u7684APPKEY |
||||
Plugin-dingtalksyn_Config_appSecret=\u5E94\u7528\u7CFB\u7EDF\u7684appSecret |
||||
Plugin-dingtalksyn_Config_appSecret_Description=\u5E94\u7528\u7CFB\u7EDF\u7684appSecret |
||||
Plugin-dingtalksyn_Config_rootDepId=\u6839\u90E8\u95E8ID |
||||
Plugin-dingtalksyn_Config_rootDepId_Description=\u6839\u90E8\u95E8ID |
Loading…
Reference in new issue