提交 6acbbbc8 编写于 作者: 楼国栋

Merge branch 'feature/welink_msg_support' into 'develop'

Welink 消息提示功能完成

See merge request o2oa/o2oa!1349
......@@ -4,5 +4,17 @@
"clientSecret": "",
"syncCron": "10 0/10 * * * ?",
"forceSyncCron": "10 45 8,12 * * ?",
"oapiAddress": "https://open.welink.huaweicloud.com/api"
"oapiAddress": "https://open.welink.huaweicloud.com/api",
"messageEnable": false,
"workUrl": "",
"messageRedirectPortal": "",
"###enable": "是否启用.###",
"###syncCron": "拉入同步cron,默认每10分钟同步一次.###",
"###forceSyncCron": "强制拉入同步cron,默认在每天的8点和12点强制进行同步.###",
"###oapiAddress": "api服务器地址###",
"###clientId": "华为WeLink轻应用的client_id###",
"###clientSecret": "华为WeLink轻应用的client_secret###",
"###messageEnable": "推送消息到华为WeLink###",
"###workUrl": "华为WeLink消息打开工作的url地址,如:http://dev.o2oa.net/x_desktop/###",
"###messageRedirectPortal": "华为WeLink消息处理完成后跳转到特定的门户页面的Id###"
}
\ No newline at end of file
......@@ -28,51 +28,51 @@ public class Messages extends ConcurrentSkipListMap<String, Message> {
o.put(MessageConnector.TYPE_ATTACHMENT_SHARE,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
o.put(MessageConnector.TYPE_ATTACHMENT_EDITOR,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
o.put(MessageConnector.TYPE_ATTACHMENT_SHARECANCEL,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
o.put(MessageConnector.TYPE_ATTACHMENT_EDITORCANCEL,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
o.put(MessageConnector.TYPE_ATTACHMENT_EDITORMODIFY,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
/* 文件通知结束 */
/* 会议通知 */
o.put(MessageConnector.TYPE_MEETING_INVITE,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
o.put(MessageConnector.TYPE_MEETING_DELETE,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
/* 会议通知结束 */
/* 待办已办通知 */
o.put(MessageConnector.TYPE_TASK_CREATE,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
/* 待办提醒通知 */
o.put(MessageConnector.TYPE_TASK_PRESS,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
o.put(MessageConnector.TYPE_TASK_DELETE, new Message());
......@@ -85,7 +85,7 @@ public class Messages extends ConcurrentSkipListMap<String, Message> {
o.put(MessageConnector.TYPE_READ_CREATE,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
o.put(MessageConnector.TYPE_READ_DELETE, new Message());
......@@ -98,7 +98,7 @@ public class Messages extends ConcurrentSkipListMap<String, Message> {
o.put(MessageConnector.TYPE_CALENDAR_ALARM,
new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
MessageConnector.CONSUME_QIYEWEIXIN));
MessageConnector.CONSUME_QIYEWEIXIN, MessageConnector.CONSUME_WELINK));
/* 文档发布消息通知 */
// o.put(MessageConnector.TYPE_CMS_PUBLISH,
......
......@@ -34,6 +34,15 @@ public class WeLink extends ConfigObject {
@FieldDescribe("WeLink api服务器地址")
private String oapiAddress;
@FieldDescribe("是否启用消息推送")
private Boolean messageEnable;
@FieldDescribe("WeLink消息打开工作的url地址,如:http://dev.o2oa.net/x_desktop/")
private String workUrl = "";
@FieldDescribe("WeLink消息处理完成后跳转到特定的门户页面的Id")
private String messageRedirectPortal = "";
public static WeLink defaultInstance() {
......@@ -46,6 +55,9 @@ public class WeLink extends ConfigObject {
public static final String default_syncCron = "10 0/10 * * * ?";
public static final String default_forceSyncCron = "10 45 8,12 * * ?";
public static final String default_oapiAddress = "https://open.welink.huaweicloud.com/api";
public static final Boolean default_messageEnable = false;
public static final String default_workUrl = "";
public static final String default_messageRedirectPortal = "";
public WeLink() {
......@@ -55,6 +67,9 @@ public class WeLink extends ConfigObject {
this.syncCron = default_syncCron;
this.forceSyncCron = default_forceSyncCron;
this.oapiAddress = default_oapiAddress;
this.messageEnable = default_messageEnable;
this.workUrl = default_workUrl;
this.messageRedirectPortal = default_messageRedirectPortal;
}
public static String WeLink_Auth_Head_Key = "x-wlk-Authorization";
......@@ -198,4 +213,28 @@ public class WeLink extends ConfigObject {
public void setOapiAddress(String oapiAddress) {
this.oapiAddress = oapiAddress;
}
public Boolean getMessageEnable() {
return BooleanUtils.isTrue(this.messageEnable);
}
public void setMessageEnable(Boolean messageEnable) {
this.messageEnable = messageEnable;
}
public String getWorkUrl() {
return StringUtils.isEmpty(this.workUrl) ? default_workUrl : this.workUrl;
}
public void setWorkUrl(String workUrl) {
this.workUrl = workUrl;
}
public String getMessageRedirectPortal() {
return StringUtils.isEmpty(this.messageRedirectPortal) ? default_messageRedirectPortal : this.messageRedirectPortal;
}
public void setMessageRedirectPortal(String messageRedirectPortal) {
this.messageRedirectPortal = messageRedirectPortal;
}
}
......@@ -129,6 +129,8 @@ public class MessageConnector {
public static final String CONSUME_DINGDING = "dingding";
public static final String CONSUME_WELINK = "welink";
public static final String CONSUME_ZHENGWUDINGDING = "zhengwuDingding";
public static final String CONSUME_QIYEWEIXIN = "qiyeweixin";
......
package com.x.base.core.project.message;
import com.x.base.core.project.gson.GsonPropertyObject;
import java.util.List;
/**
* Created by fancyLou on 2020-07-29.
* Copyright © 2020 O2. All rights reserved.
*/
public class WeLinkMessage extends GsonPropertyObject {
//{
// "msgRange": 0,0:按用户推送 必填
// "toUserList": ["john@welink", "john@1234"], 用户列表 必填
// "msgTitle": "{"EN": "hello world", "CN": "你好"}", //标题 必填 只有中文就直接写入标题字符串就行不需要json
// "msgContent": "{"CN": "欢迎使用", "EN":"Welcome"}", //消息内容 必填 只有中文就直接写入标题字符串就行不需要json
// "urlType": "html", //这两个参数是消息超链接用的 但是目前只支持小程序 不支持轻应用
// "urlPath": "h5://demo.com",
// "msgOwner": "流程平台", 消息所有者 必填
// "createTime": "1487289600000" 创建时间
//}
private String msgRange;
private List<String> toUserList;
private String msgTitle;
private String msgContent;
private String urlType;
private String urlPath;
private String msgOwner;
private String createTime;
public String getMsgRange() {
return msgRange;
}
public void setMsgRange(String msgRange) {
this.msgRange = msgRange;
}
public List<String> getToUserList() {
return toUserList;
}
public void setToUserList(List<String> toUserList) {
this.toUserList = toUserList;
}
public String getMsgTitle() {
return msgTitle;
}
public void setMsgTitle(String msgTitle) {
this.msgTitle = msgTitle;
}
public String getMsgContent() {
return msgContent;
}
public void setMsgContent(String msgContent) {
this.msgContent = msgContent;
}
public String getUrlType() {
return urlType;
}
public void setUrlType(String urlType) {
this.urlType = urlType;
}
public String getUrlPath() {
return urlPath;
}
public void setUrlPath(String urlPath) {
this.urlPath = urlPath;
}
public String getMsgOwner() {
return msgOwner;
}
public void setMsgOwner(String msgOwner) {
this.msgOwner = msgOwner;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
}
......@@ -48,6 +48,16 @@ public class Person extends GsonPropertyObject {
private String dingdingId;
@FieldDescribe("政务钉钉Id")
private String zhengwuDingdingId;
@FieldDescribe("华为WeLink id")
private String weLinkId;
public String getWeLinkId() {
return weLinkId;
}
public void setWeLinkId(String weLinkId) {
this.weLinkId = weLinkId;
}
public String getName() {
return name;
......
......@@ -33,6 +33,16 @@ public class Unit extends GsonPropertyObject {
private String dingdingId;
@FieldDescribe("政务钉钉Id")
private String zhengwuDingdingId;
@FieldDescribe("华为WeLink Id")
private String weLinkId;
public String getWeLinkId() {
return weLinkId;
}
public void setWeLinkId(String weLinkId) {
this.weLinkId = weLinkId;
}
public String getName() {
return name;
......
package com.x.message.assemble.communicate;
import com.x.base.core.project.exception.PromptException;
class ExceptionWeLinkMessage extends PromptException {
private static final long serialVersionUID = 4132300948670472899L;
ExceptionWeLinkMessage(String retCode, String retMessage) {
super("发送华为WeLink消息失败,错误代码:{},错误消息:{}.", retCode, retMessage);
}
}
......@@ -24,6 +24,8 @@ public class ThisApplication {
public static DingdingConsumeQueue dingdingConsumeQueue = new DingdingConsumeQueue();
public static WeLinkConsumeQueue weLinkConsumeQueue = new WeLinkConsumeQueue();
public static PmsInnerConsumeQueue pmsInnerConsumeQueue = new PmsInnerConsumeQueue();
public static Context context() {
......@@ -59,6 +61,9 @@ public class ThisApplication {
if (BooleanUtils.isTrue(Config.pushConfig().getEnable())) {
pmsInnerConsumeQueue.start();
}
if (Config.weLink().getEnable() && Config.weLink().getMessageEnable()) {
weLinkConsumeQueue.start();
}
MessageConnector.start(context());
......@@ -76,6 +81,7 @@ public class ThisApplication {
zhengwuDingdingConsumeQueue.stop();
dingdingConsumeQueue.stop();
pmsInnerConsumeQueue.stop();
weLinkConsumeQueue.stop();
MessageConnector.stop();
} catch (Exception e) {
e.printStackTrace();
......
package com.x.message.assemble.communicate;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.project.bean.NameValuePair;
import com.x.base.core.project.config.Config;
import com.x.base.core.project.config.WeLink;
import com.x.base.core.project.connection.HttpConnection;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.message.MessageConnector;
import com.x.base.core.project.message.WeLinkMessage;
import com.x.base.core.project.queue.AbstractQueue;
import com.x.base.core.project.tools.DefaultCharset;
import com.x.message.core.entity.Message;
import org.apache.commons.lang3.StringUtils;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class WeLinkConsumeQueue extends AbstractQueue<Message> {
private static Logger logger = LoggerFactory.getLogger(WeLinkConsumeQueue.class);
protected void execute(Message message) throws Exception {
if (Config.weLink().getEnable() && Config.weLink().getMessageEnable()) {
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
WeLinkMessage m = new WeLinkMessage();
List<String> list = new ArrayList<>();
logger.info("person :" + message.getPerson());
//todo 这里 Person.getWeLinkId() 获取不到 改用unique 不知道为啥获取不到
String unique = business.organization().person().getObject(message.getPerson()).getUnique();
if (StringUtils.isEmpty(unique)) {
logger.error(new ExceptionWeLinkMessage("-1", "没有找到对应welink用户id"));
return;
}
list.add(unique);
m.setToUserList(list);
m.setMsgRange("0");
//处理消息标题和内容
if (message.getTitle().contains(":")) {
int i = message.getTitle().indexOf(":");
m.setMsgTitle(message.getTitle().substring(0, i));
m.setMsgContent(message.getTitle().substring(i+1));
}else {
m.setMsgTitle(message.getTitle());
m.setMsgContent(message.getTitle());
}
m.setMsgOwner(appOwnerByType(message.getType()));
Date now = new Date();
m.setCreateTime(now.getTime()+"");
//是否添加超链接
if (needTransferLink(message.getType())) {
String workUrl = getDingdingOpenWorkUrl(message.getBody());
if (workUrl != null && !"".equals(workUrl)) {
m.setUrlType("html");
m.setUrlPath(workUrl);
}
}
logger.info("welink send body: " + m.toString());
String address = Config.weLink().getOapiAddress() + "/messages/v3/send";
logger.info("welink send url: " + address);
List<NameValuePair> heads = new ArrayList<>();
heads.add(new NameValuePair(WeLink.WeLink_Auth_Head_Key, Config.weLink().accessToken()));
WeLinkMessageResp resp = HttpConnection.postAsObject(address, heads, m.toString(), WeLinkMessageResp.class);
if ("0".equals(resp.getCode())) {
ExceptionWeLinkMessage e = new ExceptionWeLinkMessage(resp.getCode(), resp.getMessage());
logger.error(e);
} else {
Message messageEntityObject = emc.find(message.getId(), Message.class);
if (null != messageEntityObject) {
emc.beginTransaction(Message.class);
message.setConsumed(true);
emc.commit();
}
}
}
}
}
/**
* 生成单点登录和打开工作的地址
* @param messageBody
* @return
*/
private String getDingdingOpenWorkUrl(String messageBody) {
try {
String work = getWorkIdFromBody(messageBody);
String o2oaUrl = Config.weLink().getWorkUrl();
if (work == null || "".equals(work) || o2oaUrl == null || "".equals(o2oaUrl)) {
return null;
}
String workUrl = "workmobilewithaction.html?workid=" + work;
String messageRedirectPortal = Config.weLink().getMessageRedirectPortal();
if (messageRedirectPortal != null && !"".equals(messageRedirectPortal)) {
String portal = "portalmobile.html?id="+messageRedirectPortal;
portal = URLEncoder.encode(portal, DefaultCharset.name);
workUrl += "&redirectlink=" + portal;
}
workUrl = URLEncoder.encode(workUrl, DefaultCharset.name);
logger.info("o2oa workUrl:"+workUrl);
o2oaUrl = o2oaUrl + "welinksso.html?redirect=" + workUrl;
logger.info("o2oa 地址:"+o2oaUrl);
return o2oaUrl;
}catch (Exception e) {
logger.error(e);
}
return "";
}
/**
* 获取workid
* @param messageBody
* @return
*/
private String getWorkIdFromBody(String messageBody) {
try {
JsonObject object =new JsonParser().parse(messageBody).getAsJsonObject();
return object.get("work").getAsString();
} catch (Exception e) {
logger.error(e);
}
return "";
}
/**
* 是否需要把钉钉消息转成markdown格式消息
* 根据是否配置了钉钉工作链接、是否是工作消息(目前只支持工作消息)
* @param messageType 消息类型 判断是否是工作消息
* @return
*/
private boolean needTransferLink(String messageType) {
try {
String workUrl = Config.weLink().getWorkUrl();
if (workUrl != null && !"".equals(workUrl) && workMessageTypeList().contains(messageType)) {
return true;
}
} catch (Exception e) {
logger.error(e);
}
return false;
}
private String appOwnerByType(String messageType) {
if (workMessageTypeList().contains(messageType)) {
return "工作消息";
}else {
if (messageType.startsWith("meeting_")) {
return "会议消息";
}else if (messageType.startsWith("attachment_")) {
return "文件消息";
}else if (messageType.startsWith("calendar_")) {
return "日历消息";
}else if (messageType.startsWith("cms_")) {
return "信息中心消息";
}else if (messageType.startsWith("bbs_")) {
return "论坛消息";
}else {
return "消息";
}
}
}
private List<String> workMessageTypeList() {
List<String> list = new ArrayList<>();
list.add(MessageConnector.TYPE_WORK_TO_WORKCOMPLETED);
list.add(MessageConnector.TYPE_WORK_CREATE);
list.add(MessageConnector.TYPE_WORK_DELETE);
list.add(MessageConnector.TYPE_WORKCOMPLETED_CREATE);
list.add(MessageConnector.TYPE_WORKCOMPLETED_DELETE);
list.add(MessageConnector.TYPE_TASK_TO_TASKCOMPLETED);
list.add(MessageConnector.TYPE_TASK_CREATE);
list.add(MessageConnector.TYPE_TASK_DELETE);
list.add(MessageConnector.TYPE_TASK_URGE);
list.add(MessageConnector.TYPE_TASK_EXPIRE);
list.add(MessageConnector.TYPE_TASK_PRESS);
list.add(MessageConnector.TYPE_TASKCOMPLETED_CREATE);
list.add(MessageConnector.TYPE_TASKCOMPLETED_DELETE);
list.add(MessageConnector.TYPE_READ_TO_READCOMPLETED);
list.add(MessageConnector.TYPE_READ_CREATE);
list.add(MessageConnector.TYPE_READ_DELETE);
list.add(MessageConnector.TYPE_READCOMPLETED_CREATE);
list.add(MessageConnector.TYPE_READCOMPLETED_DELETE);
list.add(MessageConnector.TYPE_REVIEW_CREATE);
list.add(MessageConnector.TYPE_REVIEW_DELETE);
return list;
}
public static class WeLinkMessageResp {
private String code;
private String message;
private List<String> failedUserId;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<String> getFailedUserId() {
return failedUserId;
}
public void setFailedUserId(List<String> failedUserId) {
this.failedUserId = failedUserId;
}
}
}
......@@ -109,6 +109,9 @@ class ActionCreate extends BaseAction {
case MessageConnector.CONSUME_CALENDAR:
message = this.calendarMessage(effectivePerson, business, cpwi, instant);
break;
case MessageConnector.CONSUME_WELINK:
message = this.weLinkMessage(effectivePerson, business, cpwi, instant);
break;
default:
message = this.defaultMessage(effectivePerson, business, cpwi, consumer, instant);
break;
......@@ -150,6 +153,11 @@ class ActionCreate extends BaseAction {
ThisApplication.dingdingConsumeQueue.send(message);
}
break;
case MessageConnector.CONSUME_WELINK:
if (Config.weLink().getEnable() && Config.weLink().getMessageEnable()) {
ThisApplication.weLinkConsumeQueue.send(message);
}
break;
case MessageConnector.CONSUME_ZHENGWUDINGDING:
if (Config.zhengwuDingding().getEnable() && Config.zhengwuDingding().getMessageEnable()) {
ThisApplication.zhengwuDingdingConsumeQueue.send(message);
......@@ -234,6 +242,18 @@ class ActionCreate extends BaseAction {
return message;
}
private Message weLinkMessage(EffectivePerson effectivePerson, Business business, Wi wi, Instant instant) {
Message message = new Message();
message.setBody(Objects.toString(wi.getBody()));
message.setType(wi.getType());
message.setPerson(wi.getPerson());
message.setTitle(wi.getTitle());
message.setConsumer(MessageConnector.CONSUME_WELINK);
message.setConsumed(false);
message.setInstant(instant.getId());
return message;
}
private Message zhegnwudingdingMessage(EffectivePerson effectivePerson, Business business, Wi wi, Instant instant) {
Message message = new Message();
message.setBody(Objects.toString(wi.getBody()));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册