Browse Source

提交开源任务材料

10.0
LAPTOP-SB56SG4Q\86185 3 years ago
parent
commit
7a3dd1678f
  1. BIN
      JSD-8329-需求确认书.docx
  2. 5
      README.md
  3. BIN
      jsd-6890-配置使用文档.docx
  4. BIN
      lib/finekit-10.0.jar
  5. BIN
      lib/taobao-sdk-java-auto_1479188381469-20210421.jar
  6. 24
      plugin.xml
  7. 107
      src/main/java/com/fr/plugin/dingtalksyn/bean/DingTalkJobConstructor.java
  8. 83
      src/main/java/com/fr/plugin/dingtalksyn/config/DingSynConfig.java
  9. 101
      src/main/java/com/fr/plugin/dingtalksyn/helper/DingTalkScheduleHelper.java
  10. 34
      src/main/java/com/fr/plugin/dingtalksyn/job/DingTalkSyncMemberJob.java
  11. 49
      src/main/java/com/fr/plugin/dingtalksyn/provider/LifeCycleMonitorImpl.java
  12. 36
      src/main/java/com/fr/plugin/dingtalksyn/provider/LocaleFinder.java
  13. 57
      src/main/java/com/fr/plugin/dingtalksyn/request/DelegatingServletInputStream.java
  14. 78
      src/main/java/com/fr/plugin/dingtalksyn/request/GlobalRequestFilterBridge.java
  15. 81
      src/main/java/com/fr/plugin/dingtalksyn/request/ModifyBodyRequestWrapper.java
  16. 468
      src/main/java/com/fr/plugin/dingtalksyn/user/DingTalkUserManager.java
  17. 10
      src/main/resources/com/fr/plugin/dingtalksyn/locale/lang.properties
  18. 10
      src/main/resources/com/fr/plugin/dingtalksyn/locale/lang_zh_CN.properties

BIN
JSD-8329-需求确认书.docx

Binary file not shown.

5
README.md

@ -1,3 +1,6 @@
# open-JSD-8329 # open-JSD-8329
JSD-8329 开源任务材料 JSD-8329 开源任务材料\
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
仅作为开发者学习参考使用!禁止用于任何商业用途!\
为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。

BIN
jsd-6890-配置使用文档.docx

Binary file not shown.

BIN
lib/finekit-10.0.jar

Binary file not shown.

BIN
lib/taobao-sdk-java-auto_1479188381469-20210421.jar

Binary file not shown.

24
plugin.xml

@ -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.6</version>
<env-version>10.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>

107
src/main/java/com/fr/plugin/dingtalksyn/bean/DingTalkJobConstructor.java

@ -0,0 +1,107 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: DingTalkJobConstructor
* Author: Louis
* Date: 2021/4/21 15:58
*/
package com.fr.plugin.dingtalksyn.bean;
import com.fr.scheduler.job.FineScheduleJob;
/**
* <Function Description><br>
* <DingTalkJobConstructor>
*
* @author fr.open
* @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;
}
}

83
src/main/java/com/fr/plugin/dingtalksyn/config/DingSynConfig.java

@ -0,0 +1,83 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: OneAccessConfig
* Author: Louis
* 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 fr.open
* @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 = "xxxx";
public static final String APP_SECRET = "xxxx";
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);
}
}

101
src/main/java/com/fr/plugin/dingtalksyn/helper/DingTalkScheduleHelper.java

@ -0,0 +1,101 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: DingTalkScheduleHelper
* Author: Louis
* 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 fr.open
* @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;
}
// private String getSynMemberJobCron(DingTalkTimingTaskConfig var1) {
// int var2 = var1.getPeriod();
// String var3 = var1.getStartHour();
// String var4 = var1.getStartMinute();
// Week var5 = Week.getWeek(var1.getStartWeekDay());
// if (var2 == 0) {
// return String.format("%s %s %s ? * *", "0", var4, var3);
// } else {
// return var2 == 1 ? String.format("%s %s %s ? * %s", "0", var4, var3, var5) : "";
// }
// }
// public void startSynMemberSchedule(DingTalkTimingTaskConfig var1) throws Exception {
// if (var1.isEnableAutoSync()) {
// String var2 = this.getSynMemberJobCron(var1);
// DingTalkJobConstructor var3 = (new DingTalkJobConstructor()).cron(var2).jobName("DingTalkSynDepMemberJob").jobGroup("DingTalkSynDepMemberGroup").triggerName("DingTalkSynDepMemberTrigger").triggerGroup("DingTalkSynDepMemberTriggerGroup").jobClazz(DingTalkSyncMemberJob.class);
// this.startSchedule(var3);
// }
//
// }
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() {
}
}
}

34
src/main/java/com/fr/plugin/dingtalksyn/job/DingTalkSyncMemberJob.java

@ -0,0 +1,34 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: DingTalkSyncMemberJob
* Author: Louis
* 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 fr.open
* @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);
}
}
}

49
src/main/java/com/fr/plugin/dingtalksyn/provider/LifeCycleMonitorImpl.java

@ -0,0 +1,49 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: OneAccessLifeCycleMonitor
* Author: Louis
* 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.helper.DingTalkScheduleHelper;
import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
import com.fr.plugin.dingtalksyn.config.DingSynConfig;
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>
* <OneAccessLifeCycleMonitor>
*
* @author fr.open
* @since 1.0.0
*/
public class LifeCycleMonitorImpl extends AbstractPluginLifecycleMonitor {
public LifeCycleMonitorImpl() {
}
@Override
public void afterRun(PluginContext pluginContext) {
DingSynConfig.getInstance();
this.reStartSchedule();
}
@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().startSynMemberSchedule(cronCondition);
} catch (Exception e) {
LogKit.error(e.getMessage(), e);
}
}
}

36
src/main/java/com/fr/plugin/dingtalksyn/provider/LocaleFinder.java

@ -0,0 +1,36 @@
/*
* Copyright (C), 2018-2020
* Project: starter
* FileName: LocaleFinder
* Author: Louis
* 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 fr.open
* @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;
}
}

57
src/main/java/com/fr/plugin/dingtalksyn/request/DelegatingServletInputStream.java

@ -0,0 +1,57 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: DelegatingServletInputStream
* Author: Louis
* 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 fr.open
* @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) {
}
}

78
src/main/java/com/fr/plugin/dingtalksyn/request/GlobalRequestFilterBridge.java

@ -0,0 +1,78 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: GlobalRequestFilterBridge
* Author: Louis
* 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 fr.open
* @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);
}
}
}

81
src/main/java/com/fr/plugin/dingtalksyn/request/ModifyBodyRequestWrapper.java

@ -0,0 +1,81 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: UserNameTransferRequest
* Author: Louis
* 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 fr.open
* @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())));
}
}

468
src/main/java/com/fr/plugin/dingtalksyn/user/DingTalkUserManager.java

@ -0,0 +1,468 @@
/*
* Copyright (C), 2018-2021
* Project: starter
* FileName: DingTalkUserManager
* Author: Louis
* 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.*;
import com.fr.decision.authority.data.personnel.DepRole;
import com.fr.decision.privilege.TransmissionTool;
import com.fr.decision.record.OperateMessage;
import com.fr.decision.webservice.bean.user.DepartmentPostBean;
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.utils.UserSourceFactory;
import com.fr.decision.webservice.utils.WebServiceUtils;
import com.fr.decision.webservice.v10.user.CustomRoleService;
import com.fr.decision.webservice.v10.user.DepartmentService;
import com.fr.decision.webservice.v10.user.PositionService;
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.stable.StableUtils;
import com.fr.stable.StringUtils;
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 fr.open
* @since 1.0.0
*/
public final class DingTalkUserManager {
public static final String DECISION_DEP_ROOT = "decision-dep-root";
public static final String GETTOKEN = "https://oapi.dingtalk.com/gettoken";
public static final String DEPARTMENT_LIST = "https://oapi.dingtalk.com/topapi/v2/department/listsub";
public static final String GET_DEPT_MEMBER = "https://oapi.dingtalk.com/topapi/user/listid";
public static final String USER_GET = "https://oapi.dingtalk.com/topapi/v2/user/get";
public static final String ROLE_LIST = "https://oapi.dingtalk.com/topapi/role/list";
private DingSynConfig config;
private String accessToken;
public DingTalkUserManager() {
this.config = DingSynConfig.getInstance();
}
private static class HOLDER {
private static final DingTalkUserManager INSTANCE = new DingTalkUserManager();
}
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, oapiDepartment.getDeptId());
} 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, Long currentDepId) throws Exception {
UserBean userBean;
if (UserKit.existUsername(userGetResponse.getUserid())) {
userBean = updateUserBean(userGetResponse, currentDepId);
UserService.getInstance().editUser(userBean);
addUserDepartment(userBean);
} else {
userBean = createUserBean(userGetResponse, currentDepId);
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);
}
}
}
/**
* 增加用户部门关联
*
* @param userBean
* @throws Exception
*/
private void addUserDepartment(UserBean userBean) throws Exception {
if (StringUtils.isNotEmpty(userBean.getDepartmentPostId())) {
User user = UserService.getInstance().getUserByUserName(userBean.getUsername());
DepRole depRole = WebServiceUtils.parseUniqueDepartmentPostId(userBean.getDepartmentPostId());
UserSourceFactory.getInstance().checkSource(user, AuthorityContext.getInstance().getDepartmentController().getById(depRole.getDepartmentId()));
AuthorityContext.getInstance().getUserController().addUserToDepartmentAndPost(user.getId(), depRole.getDepartmentId(), depRole.getPostId());
}
}
private UserBean updateUserBean(OapiV2UserGetResponse.UserGetResponse userGetResponse, Long currentDepId) throws Exception {
User user = UserService.getInstance().getUserByUserName(userGetResponse.getUserid());
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 (userGetResponse.getRoleList() != null && !userGetResponse.getRoleList().isEmpty()) {
userBean.setRoleIds(oapiUserRoles2Ids(userGetResponse.getRoleList()));
}
if (currentDepId == null) {
return userBean;
}
String departmentPostId = String.valueOf(currentDepId);
if (StringKit.isBlank(departmentPostId) || StringKit.equals(departmentPostId, "null")) {
return userBean;
}
// 职务处理
String positionId = positionSynOperation(userGetResponse, departmentPostId);
if (StringKit.isNotBlank(positionId)) {
departmentPostId = departmentPostId + "@@@" + positionId;
}
// 旧版本jar 20210119
userBean.setDepartmentPostId(departmentPostId);
// 新版jar
// List<String> departmentPostIds = userGetResponse.getDepartment().stream().map(String::valueOf).collect(Collectors.toList());
// userBean.setDepartmentPostIds(departmentPostIds);
return userBean;
}
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;
}
private UserBean createUserBean(OapiV2UserGetResponse.UserGetResponse userGetResponse, Long currentDepId) 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 (userGetResponse.getRoleList() != null && !userGetResponse.getRoleList().isEmpty()) {
userBean.setRoleIds(oapiUserRoles2Ids(userGetResponse.getRoleList()));
}
if (currentDepId == null) {
return userBean;
}
String departmentPostId = String.valueOf(currentDepId);
if (StringKit.isBlank(departmentPostId) || StringKit.equals(departmentPostId, "null")) {
return userBean;
}
// 职务处理
String positionId = positionSynOperation(userGetResponse, departmentPostId);
if (StringKit.isNotBlank(positionId)) {
departmentPostId = departmentPostId + "@@@" + positionId;
}
// 旧版本jar 20210119
userBean.setDepartmentPostId(departmentPostId);
// 新版本jar
// List<String> departmentPostIds = userGetResponse.getDepartment().stream().map(String::valueOf).collect(Collectors.toList());
// userBean.setDepartmentPostIds(departmentPostIds);
return userBean;
}
/**
* 职务同步操作
*
* @param userGetResponse
* @param departmentId
* @return
* @throws Exception
*/
private String positionSynOperation(OapiV2UserGetResponse.UserGetResponse userGetResponse, String departmentId) throws Exception {
String position = StringKit.isNotBlank(userGetResponse.getTitle()) ? userGetResponse.getTitle() : "职员";
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.error("dingtalksyn-DingTalkUserManager-positionSynOperation-addPostToDepartmentFailed-position:{}, departmentId:{}, userID:{}, userName:{}",
positionId + position, departmentId, userGetResponse.getUserid(), userGetResponse.getName());
LogKit.error(e.getMessage(), e);
}
}
return positionId;
}
/**
* 获取管理员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();
}
}

10
src/main/resources/com/fr/plugin/dingtalksyn/locale/lang.properties

@ -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

10
src/main/resources/com/fr/plugin/dingtalksyn/locale/lang_zh_CN.properties

@ -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…
Cancel
Save