Commit 94038b3f authored by zhu-mingye's avatar zhu-mingye

Add FeiShu Alert

parent 2c2493a9
......@@ -8,8 +8,11 @@ package com.dlink.alert;
**/
public enum ShowType {
TABLE(0, "markdown"),
TEXT(1, "text");
TABLE(0, "markdown"), // 通用markdown格式
TEXT(1, "text"), //通用文本格式
POST(2, "post"), // 飞书的富文本msgType
ATTACHMENT(3, "attachment"), // 邮件相关 普通邮件
TABLE_ATTACHMENT(4, "table attachment"); // 邮件相关 邮件表格类型
private int code;
private String value;
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dlink-alert</artifactId>
<groupId>com.dlink</groupId>
<version>0.6.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dlink-alert-feishu</artifactId>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.dlink</groupId>
<artifactId>dlink-alert-base</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.dlink.alert.feishu;
import com.dlink.alert.AbstractAlert;
import com.dlink.alert.AlertResult;
/**
* FeiShuAlert
* @author zhumingye
* @date: 2022/4/2
**/
public class FeiShuAlert extends AbstractAlert {
@Override
public String getType() {
return FeiShuConstants.TYPE;
}
@Override
public AlertResult send(String title, String content) {
FeiShuSender sender = new FeiShuSender(getConfig().getParam());
return sender.send(title,content);
}
}
package com.dlink.alert.feishu;
/**
* @Author: zhumingye
* @date: 2022/4/2
* @Description: 参数常量
*/
public final class FeiShuConstants {
static final String TYPE = "FeiShu";
static final String MARKDOWN_QUOTE = "> ";
static final String MARKDOWN_ENTER = "\n";
static final String WEB_HOOK = "webhook";
static final String KEY_WORD = "keyword";
static final String SECRET = "secret";
static final String FEI_SHU_PROXY_ENABLE = "isEnableProxy";
static final String FEI_SHU_PROXY = "proxy";
static final String FEI_SHU_PORT = "port";
static final String FEI_SHU_USER = "user";
static final String FEI_SHU_PASSWORD = "password";
static final String MSG_TYPE = "msgtype";
static final String AT_ALL = "isAtAll";
static final String AT_USERS = "users";
static final String FEI_SHU_TEXT_TEMPLATE = "{\"msg_type\":\"{msg_type}\",\"content\":{\"{msg_type}\":\"{msg} {users} \" }}";
static final String FEI_SHU_POST_TEMPLATE ="{\"msg_type\":\"{msg_type}\",\"content\":{\"{msg_type}\":{\"zh_cn\":{\"title\":\"{keyword}\",\"content\":[[{\"tag\":\"text\",\"text\":\"{msg}\"},{users}]]}}}}";
private FeiShuConstants() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}
package com.dlink.alert.feishu;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
public final class HttpRequestUtil {
private HttpRequestUtil() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
public static CloseableHttpClient getHttpClient(boolean enableProxy, String proxy, Integer port, String user, String password) {
if (enableProxy) {
HttpHost httpProxy = new HttpHost(proxy, port);
CredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(new AuthScope(httpProxy), new UsernamePasswordCredentials(user, password));
return HttpClients.custom().setDefaultCredentialsProvider(provider).build();
} else {
return HttpClients.createDefault();
}
}
public static HttpPost constructHttpPost(String url, String msg) {
HttpPost post = new HttpPost(url);
StringEntity entity = new StringEntity(msg, ContentType.APPLICATION_JSON);
post.setEntity(entity);
return post;
}
}
com.dlink.alert.feishu.FeiShuAlert
\ No newline at end of file
package com.dlink.alert.feishu;
import com.dlink.alert.AlertMsg;
import com.dlink.alert.AlertResult;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: zhumingye
* @date: 2022/4/2
* @Description: 飞书消息发送 单元测试
*/
public class FeiShuSenderTest {
private static Map<String, String> feiShuConfig = new HashMap<>();
String alertMsgContentTemplate = "[\n"
+ " {\n"
+ " \"owner\": \"dlink\",\n"
+ " \"processEndTime\": \"2021-01-29 19:01:11\",\n"
+ " \"processHost\": \"10.81.129.4:5678\",\n"
+ " \"processId\": 2926,\n"
+ " \"processName\": \"3-20210129190038108\",\n"
+ " \"processStartTime\": \"2021-01-29 19:00:38\",\n"
+ " \"processState\": \"SUCCESS\",\n"
+ " \"processType\": \"START_PROCESS\",\n"
+ " \"projectId\": 2,\n"
+ " \"projectName\": \"testdelproject\",\n"
+ " \"recovery\": \"NO\",\n"
+ " \"retryTimes\": 0,\n"
+ " \"runTimes\": 1,\n"
+ " \"taskId\": 0\n"
+ " }\n"
+ "]";
@Before
public void initFeiShuConfig() {
feiShuConfig.put(FeiShuConstants.WEB_HOOK, "https://open.feishu.cn/open-apis/bot/v2/hook/aea3cd7f13154854541dsadsadas08f2a9");
feiShuConfig.put(FeiShuConstants.KEY_WORD, "Dlinky 飞书WebHook 告警测试");
feiShuConfig.put(FeiShuConstants.MSG_TYPE,"text");
feiShuConfig.put(FeiShuConstants.AT_ALL, "false");
feiShuConfig.put(FeiShuConstants.AT_USERS, "user1,user2,user3");
}
@Test
public void testTextTypeSend() {
AlertMsg alertMsg = new AlertMsg();
alertMsg.setName("Dlinky 飞书WebHook 告警测试");
alertMsg.setContent(alertMsgContentTemplate);
FeiShuSender feiShuSender = new FeiShuSender(feiShuConfig);
AlertResult alertResult = feiShuSender.send(alertMsg.getName(),alertMsg.getContent());
Assert.assertEquals(true, alertResult.getSuccess());
}
@Test
public void testPostTypeSend() {
feiShuConfig.put(FeiShuConstants.MSG_TYPE,"post");
AlertMsg alertMsg = new AlertMsg();
alertMsg.setName("Dlinky 飞书WebHook 告警测试");
alertMsg.setContent(alertMsgContentTemplate);
FeiShuSender feiShuSender = new FeiShuSender(feiShuConfig);
AlertResult alertResult = feiShuSender.send(alertMsg.getName(),alertMsg.getContent());
Assert.assertEquals(true, alertResult.getSuccess());
}
}
......@@ -15,6 +15,8 @@
<module>dlink-alert-base</module>
<module>dlink-alert-dingtalk</module>
<module>dlink-alert-wechat</module>
<module>dlink-alert-feishu</module>
<!-- <module>dlink-alert-email</module>-->
</modules>
<properties>
......
......@@ -182,6 +182,14 @@
<include>dlink-alert-wechat-${project.version}.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/dlink-alert/dlink-alert-feishu/target
</directory>
<outputDirectory>lib</outputDirectory>
<includes>
<include>dlink-alert-feishu-${project.version}.jar</include>
</includes>
</fileSet>
<!-- 将模块dlink-extends的常用jar文件放到打包目录/plugins下 -->
<!--<fileSet>
<directory>${project.parent.basedir}/dlink-extends/target
......
......@@ -85,6 +85,11 @@
<artifactId>dlink-alert-wechat</artifactId>
<scope>${scope.runtime}</scope>
</dependency>
<dependency>
<groupId>com.dlink</groupId>
<artifactId>dlink-alert-feishu</artifactId>
<scope>${scope.runtime}</scope>
</dependency>
<dependency>
<groupId>com.dlink</groupId>
<artifactId>dlink-metadata-mysql</artifactId>
......
import React, {useState} from 'react';
import {Modal,List,Card} from 'antd';
import {Card, List, Modal} from 'antd';
import {AlertInstanceTableListItem} from '../data.d';
import {connect} from "umi";
......@@ -9,6 +9,7 @@ import {AlertStateType} from "@/pages/AlertInstance/model";
import DingTalkForm from "@/pages/AlertInstance/components/DingTalkForm";
import {createOrModifyAlertInstance} from "@/pages/AlertInstance/service";
import WeChatForm from "@/pages/AlertInstance/components/WeChatForm";
import FeiShuForm from "@/pages/AlertInstance/components/FeiShuForm";
export type UpdateFormProps = {
onCancel: (flag?: boolean, formVals?: Partial<AlertInstanceTableListItem>) => void;
......@@ -101,6 +102,19 @@ const AlertInstanceChooseForm: React.FC<UpdateFormProps> = (props) => {
}}
/>:undefined
}
{(values?.type == ALERT_TYPE.FEISHU || alertType == ALERT_TYPE.FEISHU)?
<FeiShuForm
onCancel={() => {
setAlertType(undefined);
handleChooseModalVisible();
}}
modalVisible={values?.type == ALERT_TYPE.FEISHU || alertType == ALERT_TYPE.FEISHU}
values={values}
onSubmit={(value) => {
onSubmit(value);
}}
/>:undefined
}
</Modal>
);
};
......
import React, {useState} from 'react';
import {Button, Divider, Form, Input, Modal, Radio, Switch} from 'antd';
import {AlertInstanceTableListItem} from "@/pages/AlertInstance/data";
import {buildJSONData, getJSONData} from "@/pages/AlertInstance/function";
import {ALERT_TYPE} from "@/pages/AlertInstance/conf";
export type AlertInstanceFormProps = {
onCancel: (flag?: boolean) => void;
onSubmit: (values: Partial<AlertInstanceTableListItem>) => void;
modalVisible: boolean;
values: Partial<AlertInstanceTableListItem>;
};
const formLayout = {
labelCol: {span: 7},
wrapperCol: {span: 13},
};
const FeiShuForm: React.FC<AlertInstanceFormProps> = (props) => {
const [form] = Form.useForm();
const [formVals, setFormVals] = useState<Partial<AlertInstanceTableListItem>>({
id: props.values?.id,
name: props.values?.name,
type: ALERT_TYPE.FEISHU,
params: props.values?.params,
enabled: props.values?.enabled,
});
const {
onSubmit: handleSubmit,
onCancel: handleModalVisible,
modalVisible,
} = props;
const onValuesChange = (change: any,all: any)=>{
setFormVals({...formVals,...change});
};
const submitForm = async () => {
const fieldsValue = await form.validateFields();
setFormVals(buildJSONData(formVals,fieldsValue));
handleSubmit(buildJSONData(formVals,fieldsValue));
};
const renderContent = (vals) => {
return (
<>
<Divider>飞书配置</Divider>
<Form.Item
name="name"
label="名称"
rules={[{required: true, message: '请输入名称!'}]}
>
<Input placeholder="请输入名称"/>
</Form.Item>
<Form.Item
name="webhook"
label="地址"
rules={[{required: true, message: '请输入WebHook!'}]}
>
<Input placeholder="请输入WebHook"/>
</Form.Item>
<Form.Item
name="keyword"
label="关键字"
>
<Input placeholder="请输入keyword"/>
</Form.Item>
<Form.Item
name="secret"
label="密令"
>
<Input placeholder="请输入secret"/>
</Form.Item>
<Form.Item
name="isEnableProxy"
label="开启代理">
<Switch checkedChildren="是" unCheckedChildren="否"
defaultChecked={vals.isEnableProxy}/>
</Form.Item>
{vals.isEnableProxy?<>
<Form.Item
name="proxy"
label="代理"
>
<Input placeholder="请输入proxy"/>
</Form.Item>
<Form.Item
name="port"
label="端口号"
>
<Input placeholder="请输入port"/>
</Form.Item>
<Form.Item
name="user"
label="用户"
>
<Input placeholder="请输入user"/>
</Form.Item>
<Form.Item
name="password"
label="密码"
>
<Input.Password placeholder="请输入password"/>
</Form.Item></>:undefined
}
<Form.Item
name="isAtAll"
label="@所有人">
<Switch checkedChildren="启用" unCheckedChildren="禁用"
defaultChecked={vals.isAtAll}/>
</Form.Item>
{ ( !vals.isAtAll )&&
<Form.Item
name="users"
label="被@用户"
rules={[{required: true, message: '请输入被@用户!多个逗号隔开!',}]}
>
<Input placeholder="请输入被@用户ID(需要飞书后台的用户ID),多个逗号隔开!"/>
</Form.Item>
}
<Form.Item
name="enabled"
label="是否启用">
<Switch checkedChildren="启用" unCheckedChildren="禁用"
defaultChecked={vals.enabled}/>
</Form.Item>
<Form.Item
name="msgtype"
label="展示方式"
rules={[{required: true, message: '请选择展示方式!'}]}
>
<Radio.Group >
<Radio value='post'>富文本</Radio>
<Radio value='text'>文本</Radio>
</Radio.Group>
</Form.Item>
</>
);
};
const renderFooter = () => {
return (
<>
<Button onClick={() => handleModalVisible(false)}>取消</Button>
<Button type="primary" onClick={() => submitForm()}>
完成
</Button>
</>
);
};
return (
<Modal
width={1200}
bodyStyle={{padding: '32px 40px 48px'}}
destroyOnClose
title={formVals.id?"维护报警实例配置":"创建报警实例配置"}
visible={modalVisible}
footer={renderFooter()}
onCancel={() => handleModalVisible()}
>
<Form
{...formLayout}
form={form}
initialValues={getJSONData(formVals)}
onValuesChange={onValuesChange}
>
{renderContent(getJSONData(formVals))}
</Form>
</Modal>
);
};
export default FeiShuForm;
......@@ -5,10 +5,14 @@ export type AlertConfig = {
export const ALERT_TYPE = {
DINGTALK:'DingTalk',
WECHAT:'WeChat',
FEISHU:'FeiShu',
};
export const ALERT_CONFIG_LIST: AlertConfig[] = [{
type: ALERT_TYPE.DINGTALK,
},{
type: ALERT_TYPE.WECHAT,
}];
},{
type: ALERT_TYPE.FEISHU,
}
];
This diff is collapsed.
......@@ -307,6 +307,11 @@
<artifactId>dlink-alert-wechat</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.dlink</groupId>
<artifactId>dlink-alert-feishu</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.dlink</groupId>
<artifactId>dlink-daemon</artifactId>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment