From 9bd86df25c610d7ed3c257f8baa8c35c2bb612c6 Mon Sep 17 00:00:00 2001 From: "LAPTOP-SB56SG4Q\\86185" Date: Mon, 22 Nov 2021 09:55:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E5=BC=80=E6=BA=90=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=9D=90=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- JSD-8708-需求确认书V1.docx | Bin 0 -> 62992 bytes README.md | 5 +- plugin.xml | 16 + .../com/fr/plugin/patrol/sync/HttpUtil.java | 310 ++++++++++++++++++ .../plugin/patrol/sync/PluginConstants.java | 18 + .../com/fr/plugin/patrol/sync/SyncFilter.java | 76 +++++ .../patrol/sync/schedule/SyncThread.java | 243 ++++++++++++++ .../plugin/patrol/sync/schedule/UserInfo.java | 37 +++ src/main/resources/patrol.properties | 18 + 9 files changed, 722 insertions(+), 1 deletion(-) create mode 100644 JSD-8708-需求确认书V1.docx create mode 100644 plugin.xml create mode 100644 src/main/java/com/fr/plugin/patrol/sync/HttpUtil.java create mode 100644 src/main/java/com/fr/plugin/patrol/sync/PluginConstants.java create mode 100644 src/main/java/com/fr/plugin/patrol/sync/SyncFilter.java create mode 100644 src/main/java/com/fr/plugin/patrol/sync/schedule/SyncThread.java create mode 100644 src/main/java/com/fr/plugin/patrol/sync/schedule/UserInfo.java create mode 100644 src/main/resources/patrol.properties diff --git a/JSD-8708-需求确认书V1.docx b/JSD-8708-需求确认书V1.docx new file mode 100644 index 0000000000000000000000000000000000000000..1f6e64ede64c553e4e08d76ec1299f02f6e1436d GIT binary patch literal 62992 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
#wCSr|!E%?$5hCZC4 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 Ie|-0U0H_}t*Z=?k literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 64c1a17..57f7b4f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ # open-JSD-8708 -JSD-8708 开源任务材料 \ No newline at end of file +JSD-8708 OA/企业微信 (定时)角色反向同步 开源任务材料\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。 \ No newline at end of file diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..3a62394 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,16 @@ + + + com.fr.plugin.patrol.sync + + yes + 1.5 + 10.0 + 2018-07-31 + fr.open + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/patrol/sync/HttpUtil.java b/src/main/java/com/fr/plugin/patrol/sync/HttpUtil.java new file mode 100644 index 0000000..619b419 --- /dev/null +++ b/src/main/java/com/fr/plugin/patrol/sync/HttpUtil.java @@ -0,0 +1,310 @@ +package com.fr.plugin.patrol.sync; + +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.third.org.apache.http.HttpResponse; +import com.fr.third.org.apache.http.HttpStatus; +import com.fr.third.org.apache.http.client.HttpClient; +import com.fr.third.org.apache.http.client.methods.HttpPost; +import com.fr.third.org.apache.http.config.Registry; +import com.fr.third.org.apache.http.config.RegistryBuilder; +import com.fr.third.org.apache.http.conn.socket.ConnectionSocketFactory; +import com.fr.third.org.apache.http.conn.socket.PlainConnectionSocketFactory; +import com.fr.third.org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import com.fr.third.org.apache.http.entity.StringEntity; +import com.fr.third.org.apache.http.impl.client.HttpClients; +import com.fr.third.org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import com.fr.third.org.apache.http.util.EntityUtils; + +import javax.net.ssl.*; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.security.cert.CertificateException; +import java.util.Iterator; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author fr.open + * @date 2021/7/29 + */ +public class HttpUtil { + + private static HostnameVerifier hv = new HostnameVerifier() { + @Override + public boolean verify(String urlHostName, SSLSession session) { + System.out.println("Warning: URL Host: " + urlHostName + " vs. " + + session.getPeerHost()); + return true; + } + }; + + /** + * 发送get请求 + * + * @param url + * @param param + * @param header + * @return + * @throws IOException + */ + public static String sendGet(String url, Map param, Map header) { + String result = ""; + BufferedReader in = null; + String urlNameString = url; + try { + if (param != null) { + urlNameString += "?"; + urlNameString += param.entrySet() + .stream() + .map(entry -> entry.getKey() + "=" + entry.getValue()) + .collect(Collectors.joining("&")); + } + + URL realUrl = new URL(urlNameString); + // 打开和URL之间的连接 + HttpURLConnection connection; + if (url.startsWith("https")) { + trustAllHttpsCertificates(); + HttpsURLConnection.setDefaultHostnameVerifier(hv); + connection = (HttpURLConnection) realUrl.openConnection(); + } else { + connection = (HttpURLConnection) realUrl.openConnection(); + } + //设置超时时间 + connection.setDoInput(true); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(15000); + // 设置通用的请求属性 + if (header != null) { + Iterator> it = header.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + System.out.println(entry.getKey() + ":::" + entry.getValue()); + connection.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + connection.setRequestProperty("accept", "*/*"); + connection.setRequestProperty("connection", "Keep-Alive"); + connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + // 建立实际的连接 + connection.connect(); + // 定义 BufferedReader输入流来读取URL的响应,设置utf8防止中文乱码 + in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8")); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + if (in != null) { + in.close(); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, "get url error ,url is:{},error is {}", urlNameString, e.getMessage()); + } + return result; + } + + public static String sendPost(String url, Map header, JSONObject body) { + PrintWriter out = null; + BufferedReader in = null; + String result = null; + String res = null; + try { + String urlNameString = url; + + URL realUrl = new URL(urlNameString); + // 打开和URL之间的连接 + HttpURLConnection conn; + if (url.startsWith("https")) { + trustAllHttpsCertificates(); + HttpsURLConnection.setDefaultHostnameVerifier(hv); + conn = (HttpURLConnection) realUrl.openConnection(); + } else { + conn = (HttpURLConnection) realUrl.openConnection(); + } + // 设置通用的请求属性 + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); +// conn.setRequestProperty("user-agent", +// "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); + if (header != null) { + header.forEach((k, v) -> { + conn.setRequestProperty(k, String.valueOf(v)); + }); + } + // 发送POST请求必须设置如下两行 + conn.setDoOutput(true); + conn.setDoInput(true); + //获取请求头 + + // 获取URLConnection对象对应的输出流 + out = new PrintWriter(conn.getOutputStream()); + // 发送请求参数 + if (body != null) { + FineLoggerFactory.getLogger().info("content data: {}", body.toString()); + FineLoggerFactory.getLogger().info("content cover data: {}", new String(body.toString().getBytes("UTF-8"), "UTF-8")); + out.print(new String(body.toString().getBytes("UTF-8"), "UTF-8")); + } + // flush输出流的缓冲 + out.flush(); + // 定义BufferedReader输入流来读取URL的响应 + in = new BufferedReader( + new InputStreamReader(conn.getInputStream())); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + res = result; + if (res.startsWith("null")) { + res = res.replace("null", ""); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + //使用finally块来关闭输出流、输入流 + finally { + try { + if (out != null) { + out.close(); + } + if (in != null) { + in.close(); + } + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + return res; + } + + + public static String doPost(String url, Map header, JSONObject json) { + HttpClient client = HttpClients.createDefault(); + if (url.startsWith("https")) { + SSLContext sslcontext = createIgnoreVerifySSL(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.INSTANCE) + .register("https", new SSLConnectionSocketFactory(sslcontext)) + .build(); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + HttpClients.custom().setConnectionManager(connManager); + client = HttpClients.custom().setConnectionManager(connManager).build(); + } + HttpPost post = new HttpPost(url); + post.setHeader("accept", "*/*"); + post.setHeader("connection", "Keep-Alive"); + post.setHeader("Content-Type", "application/json"); + if (header != null) { + header.forEach((k, v) -> { + post.setHeader(k, String.valueOf(v)); + }); + } + try { + StringEntity s = new StringEntity(json.toString(),"UTF-8"); + s.setContentEncoding("UTF-8"); + s.setContentType("application/json; charset=UTF-8");//发送json数据需要设置contentType + post.setEntity(s); + HttpResponse res = client.execute(post); + if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + String result = EntityUtils.toString(res.getEntity());// 返回json格式: + return result; + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(),e); + } + return null; + } + + private static void trustAllHttpsCertificates() throws Exception { + TrustManager[] trustAllCerts = new TrustManager[1]; + TrustManager tm = new miTM(); + trustAllCerts[0] = tm; + SSLContext sc = SSLContext.getInstance("SSL", "SunJSSE"); + sc.init(null, trustAllCerts, null); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + } + + + /** + * encode url by UTF-8 + * + * @param url url before encoding + * @return url after encoding + */ + public static String encodeUrl(String url) { + String eurl = url; + try { + eurl = URLEncoder.encode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + } + return eurl; + } + + private static class miTM implements TrustManager, + X509TrustManager { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + public boolean isServerTrusted( + java.security.cert.X509Certificate[] certs) { + return true; + } + + public boolean isClientTrusted( + java.security.cert.X509Certificate[] certs) { + return true; + } + + @Override + public void checkServerTrusted( + java.security.cert.X509Certificate[] certs, String authType) + throws CertificateException { + return; + } + + @Override + public void checkClientTrusted( + java.security.cert.X509Certificate[] certs, String authType) + throws CertificateException { + return; + } + } + + public static SSLContext createIgnoreVerifySSL() { + try { + SSLContext sc = SSLContext.getInstance("SSLv3"); + + // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法 + X509TrustManager trustManager = new X509TrustManager() { + @Override + public void checkClientTrusted( + java.security.cert.X509Certificate[] paramArrayOfX509Certificate, + String paramString) throws CertificateException { + } + + @Override + public void checkServerTrusted( + java.security.cert.X509Certificate[] paramArrayOfX509Certificate, + String paramString) throws CertificateException { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + + sc.init(null, new TrustManager[]{trustManager}, null); + return sc; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return null; + } +} diff --git a/src/main/java/com/fr/plugin/patrol/sync/PluginConstants.java b/src/main/java/com/fr/plugin/patrol/sync/PluginConstants.java new file mode 100644 index 0000000..977e5c1 --- /dev/null +++ b/src/main/java/com/fr/plugin/patrol/sync/PluginConstants.java @@ -0,0 +1,18 @@ +package com.fr.plugin.patrol.sync; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * @Author fr.open + * @Date 2021/3/1 + * @Description + **/ +public class PluginConstants { + + public static final String PLUGIN_ID = "com.fr.plugin.patrol.sync"; + + public static Set NAMES = new HashSet(Arrays.asList(new String[]{"安监日报","营销BI-xxxx","营销BI-xxx","营销BI-xx"})); + +} diff --git a/src/main/java/com/fr/plugin/patrol/sync/SyncFilter.java b/src/main/java/com/fr/plugin/patrol/sync/SyncFilter.java new file mode 100644 index 0000000..7136ddf --- /dev/null +++ b/src/main/java/com/fr/plugin/patrol/sync/SyncFilter.java @@ -0,0 +1,76 @@ +package com.fr.plugin.patrol.sync; + +import com.fr.base.PropertiesUtils; +import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; +import com.fr.intelli.record.Focus; +import com.fr.intelli.record.Original; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.context.PluginContexts; +import com.fr.plugin.patrol.sync.schedule.SyncThread; +import com.fr.plugin.transform.FunctionRecorder; +import com.fr.record.analyzer.EnableMetrics; +import com.fr.scheduler.QuartzContext; +import com.fr.scheduler.ScheduleJobManager; +import com.fr.stable.StringUtils; +import com.fr.stable.fun.Authorize; +import com.fr.third.v2.org.quartz.CronScheduleBuilder; +import com.fr.third.v2.org.quartz.JobKey; +import com.fr.third.v2.org.quartz.SchedulerException; +import com.fr.third.v2.org.quartz.TriggerBuilder; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Author fr.open + * @Date 2021/7/29 + * @Description + **/ +@FunctionRecorder +@Authorize(callSignKey = PluginConstants.PLUGIN_ID) +@EnableMetrics +public class SyncFilter extends AbstractGlobalRequestFilterProvider { + @Override + public String filterName() { + return "syncPatrol"; + } + + @Override + @Focus(id = PluginConstants.PLUGIN_ID, text = "门户角色同步", source = Original.PLUGIN) + public String[] urlPatterns() { + if (PluginContexts.currentContext().isAvailable()) { + initSchedule(); + } + return new String[]{"/syncPatrol"}; + } + + public static void initSchedule() { + JobKey jobKey = new JobKey("syncPatrol", "syncGroup"); + try { + if (QuartzContext.getInstance().getScheduler().checkExists(jobKey)) { + ScheduleJobManager.getInstance().removeJob(jobKey.getName(), jobKey.getGroup()); + } + } catch (SchedulerException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + addSchedule(jobKey); + } + + private static void addSchedule(JobKey jobKey) { + Map param = new HashMap(); + TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger(); + triggerBuilder.forJob(jobKey.getName(), jobKey.getGroup()).withIdentity(jobKey.getName(), jobKey.getGroup()).startNow(); + String cron = PropertiesUtils.getProperties("patrol").getProperty("cron"); + if (StringUtils.isBlank(cron)) { + FineLoggerFactory.getLogger().error("cron is null schedule start failed"); + return; + } + CronScheduleBuilder schedule = CronScheduleBuilder.cronSchedule(cron); + triggerBuilder.withSchedule(schedule); + try { + ScheduleJobManager.getInstance().addJob(jobKey.getName(), jobKey.getGroup(), "sync job", SyncThread.class, triggerBuilder.build(), param); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } +} diff --git a/src/main/java/com/fr/plugin/patrol/sync/schedule/SyncThread.java b/src/main/java/com/fr/plugin/patrol/sync/schedule/SyncThread.java new file mode 100644 index 0000000..6ce3474 --- /dev/null +++ b/src/main/java/com/fr/plugin/patrol/sync/schedule/SyncThread.java @@ -0,0 +1,243 @@ +package com.fr.plugin.patrol.sync.schedule; + +import com.fr.base.TableData; +import com.fr.cluster.core.ClusterNode; +import com.fr.decision.authority.AuthorityContext; +import com.fr.decision.authority.data.CustomRole; +import com.fr.decision.authority.data.User; +import com.fr.decision.webservice.service.user.UserMiddleRoleService; +import com.fr.file.TableDataConfig; +import com.fr.general.PropertiesUtils; +import com.fr.general.data.DataModel; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.patrol.sync.HttpUtil; +import com.fr.plugin.patrol.sync.PluginConstants; +import com.fr.scheduler.job.FineScheduleJob; +import com.fr.script.Calculator; +import com.fr.stable.StringUtils; +import com.fr.stable.query.QueryFactory; +import com.fr.third.v2.org.quartz.JobExecutionContext; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Author fr.open + * @Date 2021/7/29 + * @Description + **/ +public class SyncThread extends FineScheduleJob { + + private DataModel dataModel; + + private String addRole; + + private String getUser; + + private String addUser; + + private String deleteUser; + + private String createId; + + private String findRole; + + private String editRole; + + + public SyncThread() { + String name = PropertiesUtils.getProperties("patrol").getProperty("name"); + FineLoggerFactory.getLogger().info("get table data config is {}", name); + + addRole = PropertiesUtils.getProperties("patrol").getProperty("addRole"); + FineLoggerFactory.getLogger().info("get addRole config is {}", addRole); + + getUser = PropertiesUtils.getProperties("patrol").getProperty("getUser"); + FineLoggerFactory.getLogger().info("get getUser config is {}", getUser); + + addUser = PropertiesUtils.getProperties("patrol").getProperty("addUser"); + FineLoggerFactory.getLogger().info("get addUser config is {}", addUser); + + deleteUser = PropertiesUtils.getProperties("patrol").getProperty("deleteUser"); + FineLoggerFactory.getLogger().info("get deleteUser config is {}", deleteUser); + + createId = PropertiesUtils.getProperties("patrol").getProperty("createId"); + FineLoggerFactory.getLogger().info("get createId config is {}", createId); + + findRole = PropertiesUtils.getProperties("patrol").getProperty("findRole"); + FineLoggerFactory.getLogger().info("get findRole config is {}", findRole); + + editRole = PropertiesUtils.getProperties("patrol").getProperty("editRole"); + FineLoggerFactory.getLogger().info("get editRole config is {}", editRole); + TableData tableData = TableDataConfig.getInstance().getTableData(name); + dataModel = tableData.createDataModel(Calculator.createCalculator()); + } + + @Override + public void run(JobExecutionContext jobExecutionContext, ClusterNode clusterNode) throws Exception { + List customRoles = AuthorityContext.getInstance().getCustomRoleController().find(QueryFactory.create()); + customRoles = customRoles.stream().filter(e -> !"superusers".equals(e.getName())).collect(Collectors.toList()); + FineLoggerFactory.getLogger().info("get role size is {}", customRoles.size()); + Map roleMap = getRoleMap(); + if(roleMap.isEmpty() || roleMap.size() < 4){ + FineLoggerFactory.getLogger().error("default tag is not exist,map is {}",roleMap); + return; + } + Map> remoteMap = new HashMap<>(); + Map> existMap = new HashMap<>(); + for(CustomRole role : customRoles) { + String roleName = getTagName(role.getName()); + if (StringUtils.isBlank(roleName)) { + FineLoggerFactory.getLogger().info("role {} get Mapping failed"); + continue; + } + String roleCode = roleMap.get(roleName); + //系统下的角色用户 + Map users = getUsers(role.getId()); + //门户角色下用户 + Set roleUsers = getRoleUser(roleCode); + remoteMap.put(roleCode,roleUsers); + Set ids = existMap.get(roleCode); + if(ids == null){ + ids = new HashSet<>(); + } + ids.addAll(users.keySet()); + existMap.put(roleCode,ids); + + Set add = users.keySet().stream().filter(e -> !roleUsers.contains(e)).collect(Collectors.toSet()); + addRoleUser(roleCode, add); + + } + + remoteMap.forEach((k,v)->{ + Set ids = existMap.get(k); + Set delete = v.stream().filter(e -> !ids.contains(e)).collect(Collectors.toSet()); + FineLoggerFactory.getLogger().info("remote users is {} exist users is {}",v,ids); + FineLoggerFactory.getLogger().info("delete users {} to tag:{}",delete,k); + deleteRoleUser(k, delete); + }); + /*Map roleMap = getRoleMap(); + for (CustomRole role : customRoles) { + String roleCode = role.getId().replace("-", ""); + if (roleMap.containsKey(roleCode)) { + //角色名称不同则更新角色名称 + if (!role.getName().equals(roleMap.get(roleCode))) { + editRole(roleCode, role.getName()); + } + } else { + //首先新建角色 + roleCode = addRole(role); + } + //系统下的角色用户 + Map users = getUsers(role.getId()); + //门户角色下用户 + Set roleUsers = getRoleUser(roleCode); + + Set delete = roleUsers.stream().filter(e -> !users.keySet().contains(e)).collect(Collectors.toSet()); + deleteRoleUser(roleCode, delete); + + Set add = users.keySet().stream().filter(e -> !delete.contains(e)).collect(Collectors.toSet()); + addRoleUser(roleCode, add); + + }*/ + } + private String getTagName(String name) { + Iterator iterator = PluginConstants.NAMES.iterator(); + while (iterator.hasNext()){ + String key = iterator.next(); + if(key.equals("安监日报") && name.startsWith("安监-")){ + return key; + } + if(name.startsWith(key)){ + return key; + } + } + return StringUtils.EMPTY; + } + + private void editRole(String code, String name) { + String res = HttpUtil.sendPost(editRole, null, new JSONObject().put("roleId", code).put("roleName", name).put("createId", createId)); + FineLoggerFactory.getLogger().info("edit role res is {}", res); + } + + private Map getRoleMap() { + String res = HttpUtil.sendPost(findRole, null, new JSONObject().put("createId", createId)); + FineLoggerFactory.getLogger().info("get role res is {}", res); + JSONObject object = new JSONObject(res); + Map map = new HashMap<>(); + JSONArray date = object.getJSONArray("data"); + for (int i = 0; i < date.size(); i++) { + JSONObject entries = date.getJSONObject(i); + if(PluginConstants.NAMES.contains(entries.getString("roleName"))){ + map.put(entries.getString("roleName"),entries.getString("roleId")); + } + } + return map; + } + + private void addRoleUser(String roleCode, Set add) { + if (add == null || add.isEmpty()) { + return; + } + Iterator it = add.iterator(); + while (it.hasNext()) { + String next = it.next(); + String res = HttpUtil.sendPost(addUser, null, new JSONObject().put("roleId", roleCode).put("authorizationUser", next).put("createId", createId)); + FineLoggerFactory.getLogger().info("add role users res is {}", res); + } + } + + private void deleteRoleUser(String roleCode, Set delete) { + if (delete == null || delete.isEmpty()) { + return; + } + Iterator it = delete.iterator(); + while (it.hasNext()) { + String next = it.next(); + String res = HttpUtil.sendPost(deleteUser, null, new JSONObject().put("roleId", roleCode).put("authorizationUser", next).put("createId", createId)); + FineLoggerFactory.getLogger().info("delete role users res is {}", res); + } + } + + private Set getRoleUser(String roleCode) { + String res = HttpUtil.sendPost(getUser, null, new JSONObject().put("roleId", roleCode).put("createId", createId)); + FineLoggerFactory.getLogger().info("get role users res is {}", res); + JSONObject object = new JSONObject(res); + JSONArray date = object.getJSONObject("data").getJSONArray("userAuth"); + Set users = new HashSet<>(); + for (int i = 0; i < date.size(); i++) { + JSONObject entries = date.getJSONObject(i); + users.add(entries.getString("userCode")); + } + return users; + } + + private String addRole(CustomRole role) { + String code = role.getId().replaceAll("-", ""); + JSONObject object = new JSONObject().put("roleId", code).put("roleName", role.getName()).put("createId", createId); + String res = HttpUtil.sendPost(addRole, null, object); + FineLoggerFactory.getLogger().info("add role res is {}", res); + return code; + } + + + private Map getUsers(String roleId) throws Exception { + Set ids = UserMiddleRoleService.getInstance().getAllUserIdsByCustomRole(roleId); + List all = AuthorityContext.getInstance().getUserController().find(QueryFactory.create()); + Set usersMap = all.stream().filter(e -> ids.contains(e.getId())).map(e -> e.getUserName()).collect(Collectors.toSet()); + Map result = new HashMap<>(); + try { + for (int i = 0; i < dataModel.getRowCount(); i++) { + Object valueAt = dataModel.getValueAt(i, 4); + if (valueAt != null && usersMap.contains(valueAt.toString())) { + result.put(String.valueOf(dataModel.getValueAt(i, 7)), valueAt.toString()); + } + } + } catch (Exception e) { + + } + return result; + } +} diff --git a/src/main/java/com/fr/plugin/patrol/sync/schedule/UserInfo.java b/src/main/java/com/fr/plugin/patrol/sync/schedule/UserInfo.java new file mode 100644 index 0000000..fbb4fd0 --- /dev/null +++ b/src/main/java/com/fr/plugin/patrol/sync/schedule/UserInfo.java @@ -0,0 +1,37 @@ +package com.fr.plugin.patrol.sync.schedule; + +/** + * @Author fr.open + * @Date 2021/7/29 + * @Description + **/ +public class UserInfo { + + private String name; + + private String id; + + public UserInfo() { + } + + public UserInfo(String name, String id) { + this.name = name; + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} diff --git a/src/main/resources/patrol.properties b/src/main/resources/patrol.properties new file mode 100644 index 0000000..54508c9 --- /dev/null +++ b/src/main/resources/patrol.properties @@ -0,0 +1,18 @@ +##定时器参数,此配置为默认每小时执行一次 +cron=0 0/1 * * * ? * +##增加角色 +addRole=http://ip:port/api/FndRole/add +##获取角色下用户 +getUser=http://ip:port/api/FndRole/getUserList +##向角色添加用户 +addUser=http://ip:port/api/FndRole/addUser +##向角色删除角色 +deleteUser=http://ip:port/api/FndRole/deleteUser +##更新角色 +editRole=http://ip:port/api/FndRole/roleModify +##获取角色 +findRole=http://ip:port/api/FndRole/getRoleList +##授权系统 +createId=xxxx +##数据集名称 +name=xxxx \ No newline at end of file