mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-09-17 18:19:02 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abdf3df92c | ||
|
|
0211a80f6b |
+2
-23
@@ -17,30 +17,9 @@
|
||||
|
||||
package org.apache.hertzbeat.alert.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Alibaba Cloud SMS configuration properties
|
||||
* Alibaba Cloud SMS properties
|
||||
*/
|
||||
@Data
|
||||
public class AlibabaSmsProperties {
|
||||
/**
|
||||
* Alibaba Cloud access key id
|
||||
*/
|
||||
private String accessKeyId;
|
||||
|
||||
/**
|
||||
* Alibaba Cloud access key secret
|
||||
*/
|
||||
private String accessKeySecret;
|
||||
|
||||
/**
|
||||
* SMS signature
|
||||
*/
|
||||
private String signName;
|
||||
|
||||
/**
|
||||
* SMS template Code
|
||||
*/
|
||||
private String templateCode;
|
||||
// todo add properties
|
||||
}
|
||||
|
||||
@@ -49,9 +49,4 @@ public class SmsConfig {
|
||||
*/
|
||||
private AlibabaSmsProperties alibaba;
|
||||
|
||||
/**
|
||||
* UniSMS configuration
|
||||
*/
|
||||
private UniSmsProperties unisms;
|
||||
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.alert.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* UniSMS properties
|
||||
*/
|
||||
@Data
|
||||
public class UniSmsProperties {
|
||||
/**
|
||||
* UniSMS access key id
|
||||
*/
|
||||
private String accessKeyId;
|
||||
|
||||
/**
|
||||
* UniSMS access key secret, required for HMAC mode
|
||||
*/
|
||||
private String accessKeySecret;
|
||||
|
||||
/**
|
||||
* SMS signature
|
||||
*/
|
||||
private String signature;
|
||||
|
||||
/**
|
||||
* SMS template ID
|
||||
*/
|
||||
private String templateId;
|
||||
|
||||
/**
|
||||
* Authentication mode: simple or hmac, default is simple
|
||||
*/
|
||||
private String authMode = "simple";
|
||||
}
|
||||
+1
-7
@@ -21,8 +21,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.alert.config.SmsConfig;
|
||||
import org.apache.hertzbeat.alert.service.impl.TencentSmsClientImpl;
|
||||
import org.apache.hertzbeat.alert.service.impl.UniSmsClientImpl;
|
||||
import org.apache.hertzbeat.alert.service.impl.AlibabaSmsClientImpl;
|
||||
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
|
||||
import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum;
|
||||
import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
|
||||
@@ -32,7 +30,6 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.ALIBABA;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.TENCENT;
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.UNISMS;
|
||||
|
||||
/**
|
||||
* SMS client factory
|
||||
@@ -127,11 +124,8 @@ public class SmsClientFactory {
|
||||
case TENCENT:
|
||||
currentSmsClient = new TencentSmsClientImpl(smsConfig.getTencent());
|
||||
break;
|
||||
case UNISMS:
|
||||
currentSmsClient = new UniSmsClientImpl(smsConfig.getUnisms());
|
||||
break;
|
||||
case ALIBABA:
|
||||
currentSmsClient = new AlibabaSmsClientImpl(smsConfig.getAlibaba());
|
||||
// TODO: implement Alibaba SMS client
|
||||
break;
|
||||
default:
|
||||
log.warn("[SmsClientFactory] Unsupported SMS provider type: {}", smsConfig.getType());
|
||||
|
||||
-234
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.alert.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.alert.config.AlibabaSmsProperties;
|
||||
import org.apache.hertzbeat.alert.service.SmsClient;
|
||||
import org.apache.hertzbeat.alert.util.CryptoUtils;
|
||||
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
|
||||
import org.apache.hertzbeat.common.support.exception.SendMessageException;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.ALIBABA;
|
||||
|
||||
/**
|
||||
* Alibaba Cloud SMS Client Implementation<br>
|
||||
* API doc: <a href="https://next.api.aliyun.com/document/Dysmsapi/2017-05-25/SendSms">https://next.api.aliyun.com/document/Dysmsapi/2017-05-25/SendSms</a><br>
|
||||
* Singnature doc: <a href="https://help.aliyun.com/zh/sdk/product-overview/v3-request-structure-and-signature">https://help.aliyun.com/zh/sdk/product-overview/v3-request-structure-and-signature</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class AlibabaSmsClientImpl implements SmsClient {
|
||||
|
||||
private static final String API_VERSION = "2017-05-25";
|
||||
private static final String ACTION = "SendSms";
|
||||
private static final String HOST = "dysmsapi.aliyuncs.com";
|
||||
private static final String ALGORITHM = "ACS3-HMAC-SHA256";
|
||||
|
||||
private final String accessKeyId;
|
||||
private final String accessKeySecret;
|
||||
private final String signName;
|
||||
private final String templateCode;
|
||||
|
||||
public AlibabaSmsClientImpl(AlibabaSmsProperties config) {
|
||||
if (config != null) {
|
||||
this.accessKeyId = config.getAccessKeyId();
|
||||
this.accessKeySecret = config.getAccessKeySecret();
|
||||
this.signName = config.getSignName();
|
||||
this.templateCode = config.getTemplateCode();
|
||||
} else {
|
||||
this.accessKeyId = "";
|
||||
this.accessKeySecret = "";
|
||||
this.signName = "";
|
||||
this.templateCode = "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) {
|
||||
// Extract alert info
|
||||
String instance = null;
|
||||
String priority = null;
|
||||
String content = null;
|
||||
if (alert.getCommonLabels() != null) {
|
||||
instance = alert.getCommonLabels().get("instance");
|
||||
priority = alert.getCommonLabels().get("priority");
|
||||
content = alert.getCommonAnnotations().get("summary");
|
||||
content = content == null ? alert.getCommonAnnotations().get("description") : content;
|
||||
if (content == null) {
|
||||
content = alert.getCommonAnnotations().values().stream().findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Build template parameters
|
||||
Map<String, String> templateParam = new HashMap<>();
|
||||
templateParam.put("instance", instance == null ? alert.getGroupKey() : instance);
|
||||
templateParam.put("priority", priority == null ? "unknown" : priority);
|
||||
templateParam.put("content", content);
|
||||
|
||||
sendSms(receiver.getPhone(), JsonUtil.toJson(templateParam));
|
||||
}
|
||||
|
||||
private void sendSms(String phoneNumber, String templateParam) {
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
// Build query parameters
|
||||
Map<String, String> queryParams = new TreeMap<>();
|
||||
queryParams.put("PhoneNumbers", phoneNumber);
|
||||
queryParams.put("SignName", signName);
|
||||
queryParams.put("TemplateCode", templateCode);
|
||||
queryParams.put("TemplateParam", templateParam);
|
||||
|
||||
// Build canonical query string
|
||||
StringBuilder canonicalQueryString = new StringBuilder();
|
||||
queryParams.forEach((key, value) -> {
|
||||
if (canonicalQueryString.length() > 0) {
|
||||
canonicalQueryString.append("&");
|
||||
}
|
||||
canonicalQueryString.append(percentEncode(key))
|
||||
.append("=")
|
||||
.append(percentEncode(value));
|
||||
});
|
||||
|
||||
// Generate timestamp and nonce
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
sdf.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||
String timestamp = sdf.format(new Date());
|
||||
String nonce = UUID.randomUUID().toString();
|
||||
|
||||
// Calculate signature
|
||||
String authorization = calculateAuthorization(
|
||||
canonicalQueryString.toString(),
|
||||
timestamp,
|
||||
nonce
|
||||
);
|
||||
|
||||
// Build URL
|
||||
String url = "https://" + HOST + "/?" + canonicalQueryString;
|
||||
|
||||
// Build HTTP request
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
httpPost.setHeader("Content-Type", "application/json");
|
||||
httpPost.setHeader("Host", HOST);
|
||||
httpPost.setHeader("Authorization", authorization);
|
||||
httpPost.setHeader("x-acs-action", ACTION);
|
||||
httpPost.setHeader("x-acs-version", API_VERSION);
|
||||
httpPost.setHeader("x-acs-date", timestamp);
|
||||
httpPost.setHeader("x-acs-signature-nonce", nonce);
|
||||
httpPost.setHeader("x-acs-content-sha256",
|
||||
CryptoUtils.sha256Hex(""));
|
||||
|
||||
log.info("Sending Alibaba SMS request to {}", url + ", params: " + templateParam + "headers: " + Arrays.toString(httpPost.getAllHeaders()));
|
||||
|
||||
// Send request and handle response
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
String responseBody = EntityUtils.toString(response.getEntity());
|
||||
|
||||
log.info("SMS response status: {}, body: {}", statusCode, responseBody);
|
||||
|
||||
if (statusCode != 200) {
|
||||
throw new SendMessageException("HTTP request failed with status code: " + statusCode + ", response: " + responseBody);
|
||||
}
|
||||
|
||||
JsonNode jsonResponse = JsonUtil.fromJson(responseBody);
|
||||
String code = jsonResponse.get("Code").asText();
|
||||
if (!"OK".equals(code)) {
|
||||
String message = jsonResponse.get("Message").asText();
|
||||
throw new SendMessageException(code + ":" + message);
|
||||
}
|
||||
|
||||
log.info("Successfully sent SMS to phone: {}", phoneNumber);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to send SMS: {}", e.getMessage());
|
||||
throw new SendMessageException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String calculateAuthorization(String canonicalQueryString, String timestamp, String nonce) {
|
||||
try {
|
||||
// Step 1: Build canonical request
|
||||
String canonicalRequest = buildCanonicalRequest(canonicalQueryString, timestamp, nonce);
|
||||
|
||||
// Step 2: Build string to sign
|
||||
String stringToSign = ALGORITHM + "\n" + CryptoUtils.sha256Hex(canonicalRequest);
|
||||
|
||||
// Step 3: Calculate signature
|
||||
String signature = CryptoUtils.hmacSha256Hex(accessKeySecret, stringToSign);
|
||||
|
||||
// Step 4: Build authorization header
|
||||
return ALGORITHM + " Credential=" + accessKeyId + ",SignedHeaders=host;x-acs-action;x-acs-content-sha256;x-acs-date;" + "x-acs-signature-nonce;x-acs-version,Signature=" + signature;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to calculate authorization", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String buildCanonicalRequest(String canonicalQueryString, String timestamp, String nonce) {
|
||||
return "POST\n"
|
||||
+ "/\n"
|
||||
+ canonicalQueryString + "\n"
|
||||
+ "host:" + HOST + "\n"
|
||||
+ "x-acs-action:" + ACTION + "\n"
|
||||
+ "x-acs-content-sha256:" + CryptoUtils.sha256Hex("") + "\n"
|
||||
+ "x-acs-date:" + timestamp + "\n"
|
||||
+ "x-acs-signature-nonce:" + nonce + "\n"
|
||||
+ "x-acs-version:" + API_VERSION + "\n\n"
|
||||
+ "host;x-acs-action;x-acs-content-sha256;x-acs-date;"
|
||||
+ "x-acs-signature-nonce;x-acs-version\n"
|
||||
+ CryptoUtils.sha256Hex("");
|
||||
}
|
||||
|
||||
private String percentEncode(String value) {
|
||||
try {
|
||||
return java.net.URLEncoder.encode(value, StandardCharsets.UTF_8)
|
||||
.replace("+", "%20")
|
||||
.replace("*", "%2A")
|
||||
.replace("%7E", "~");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to encode value", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return ALIBABA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkConfig() {
|
||||
return !(accessKeyId.isBlank() || accessKeySecret.isBlank() || signName.isBlank() || templateCode.isBlank());
|
||||
}
|
||||
}
|
||||
+2
-44
@@ -20,7 +20,7 @@ package org.apache.hertzbeat.alert.service.impl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.alert.config.TencentSmsProperties;
|
||||
import org.apache.hertzbeat.alert.service.SmsClient;
|
||||
import org.apache.hertzbeat.alert.util.CryptoUtils;
|
||||
import org.apache.hertzbeat.alert.util.TencentCloudApiSignV3;
|
||||
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
|
||||
@@ -34,14 +34,9 @@ import org.apache.http.util.EntityUtils;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.TENCENT;
|
||||
|
||||
@@ -58,7 +53,6 @@ public class TencentSmsClientImpl implements SmsClient {
|
||||
private static final String API_VERSION = "2021-01-11";
|
||||
private static final String ACTION = "SendSms";
|
||||
private static final String HOST = "sms.tencentcloudapi.com";
|
||||
private static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||
|
||||
private String appId;
|
||||
private String signName;
|
||||
@@ -119,7 +113,7 @@ public class TencentSmsClientImpl implements SmsClient {
|
||||
String payload = JsonUtil.toJson(params);
|
||||
|
||||
// calculate request signature
|
||||
String authorization = calculateAuthorization(
|
||||
String authorization = TencentCloudApiSignV3.calculateAuthorization(
|
||||
secretId, secretKey, "sms", HOST, REGION,
|
||||
ACTION, API_VERSION, payload);
|
||||
|
||||
@@ -184,40 +178,4 @@ public class TencentSmsClientImpl implements SmsClient {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String calculateAuthorization(String secretId, String secretKey,
|
||||
String service, String host, String region,
|
||||
String action, String version, String payload) throws Exception {
|
||||
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
|
||||
|
||||
// Step 1: Construct the canonical request string
|
||||
String httpRequestMethod = "POST";
|
||||
String canonicalUri = "/";
|
||||
String canonicalQueryString = "";
|
||||
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n";
|
||||
String signedHeaders = "content-type;host";
|
||||
String hashedRequestPayload = CryptoUtils.sha256Hex(payload);
|
||||
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
|
||||
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
|
||||
|
||||
// Step 2: Construct the string to sign
|
||||
String algorithm = "TC3-HMAC-SHA256";
|
||||
String credentialScope = date + "/" + service + "/" + "tc3_request";
|
||||
String hashedCanonicalRequest = CryptoUtils.sha256Hex(canonicalRequest);
|
||||
String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
|
||||
|
||||
// Step 3: Calculate the signature
|
||||
byte[] secretDate = CryptoUtils.hmac256(("TC3" + secretKey).getBytes(UTF8), date);
|
||||
byte[] secretService = CryptoUtils.hmac256(secretDate, service);
|
||||
byte[] secretSigning = CryptoUtils.hmac256(secretService, "tc3_request");
|
||||
String signature = DatatypeConverter.printHexBinary(
|
||||
CryptoUtils.hmac256(secretSigning, stringToSign)).toLowerCase();
|
||||
|
||||
// Step 4: Construct the Authorization header
|
||||
return algorithm + " " + "Credential=" + secretId + "/" + credentialScope + ", "
|
||||
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
|
||||
}
|
||||
}
|
||||
|
||||
-193
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.alert.service.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.alert.config.UniSmsProperties;
|
||||
import org.apache.hertzbeat.alert.service.SmsClient;
|
||||
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
|
||||
import org.apache.hertzbeat.common.support.exception.SendMessageException;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.apache.hertzbeat.alert.util.CryptoUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.hertzbeat.common.constants.SmsConstants.UNISMS;
|
||||
|
||||
/**
|
||||
* UniSMS client implementation <br/>
|
||||
* doc:<a href="https://unisms.apistd.com/docs/api/send">https://unisms.apistd.com/docs/api/send</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class UniSmsClientImpl implements SmsClient {
|
||||
|
||||
private static final String API_URL = "https://uni.apistd.com";
|
||||
private static final String ACTION = "sms.message.send";
|
||||
private static final String SUCCESS_CODE = "0";
|
||||
private static final String HMAC_ALGORITHM = "hmac-sha256";
|
||||
|
||||
private final UniSmsProperties config;
|
||||
|
||||
public UniSmsClientImpl(UniSmsProperties config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) {
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
// build request parameters
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("to", receiver.getPhone());
|
||||
params.put("signature", config.getSignature());
|
||||
params.put("templateId", config.getTemplateId());
|
||||
|
||||
// build template data
|
||||
Map<String, String> templateData = new HashMap<>();
|
||||
String instance = alert.getCommonLabels().getOrDefault("instance", alert.getGroupKey());
|
||||
String priority = alert.getCommonLabels().getOrDefault("priority", "unknown");
|
||||
String content = alert.getCommonAnnotations().get("summary");
|
||||
content = content == null ? alert.getCommonAnnotations().get("description") : content;
|
||||
if (content == null) {
|
||||
content = alert.getCommonAnnotations().values().stream().findFirst().orElse(null);
|
||||
}
|
||||
|
||||
templateData.put("instance", instance);
|
||||
templateData.put("priority", priority);
|
||||
templateData.put("content", content);
|
||||
params.put("templateData", templateData);
|
||||
|
||||
// build URL and request headers
|
||||
String url;
|
||||
if ("hmac".equalsIgnoreCase(config.getAuthMode())) {
|
||||
url = buildHmacUrl();
|
||||
} else {
|
||||
url = buildSimpleUrl();
|
||||
}
|
||||
|
||||
// send HTTP request
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
httpPost.setHeader("Content-Type", "application/json");
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
|
||||
String payload = JsonUtil.toJson(params);
|
||||
httpPost.setEntity(new StringEntity(payload, StandardCharsets.UTF_8));
|
||||
|
||||
log.info("Sending SMS request to UniSMS, payload: {}, url: {}", payload, url);
|
||||
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
handleResponse(response, receiver.getPhone());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send SMS via UniSMS: {}", e.getMessage());
|
||||
throw new SendMessageException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String buildSimpleUrl() {
|
||||
return String.format("%s/?action=%s&accessKeyId=%s",
|
||||
API_URL, ACTION, config.getAccessKeyId());
|
||||
}
|
||||
|
||||
private String buildHmacUrl() {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String nonce = generateNonce();
|
||||
|
||||
// build query parameters
|
||||
Map<String, String> params = new TreeMap<>();
|
||||
params.put("accessKeyId", config.getAccessKeyId());
|
||||
params.put("action", ACTION);
|
||||
params.put("algorithm", HMAC_ALGORITHM);
|
||||
params.put("nonce", nonce);
|
||||
params.put("timestamp", String.valueOf(timestamp));
|
||||
|
||||
// build sign text
|
||||
String signText = params.entrySet().stream()
|
||||
.map(entry -> entry.getKey() + "=" + entry.getValue())
|
||||
.collect(Collectors.joining("&"));
|
||||
|
||||
// calculate signature
|
||||
String signature = CryptoUtils.hmacSha256Base64(config.getAccessKeySecret(), signText);
|
||||
return String.format("%s/?action=%s&accessKeyId=%s&algorithm=%s×tamp=%d&nonce=%s&signature=%s",
|
||||
API_URL, ACTION, config.getAccessKeyId(), HMAC_ALGORITHM, timestamp, nonce, signature);
|
||||
}
|
||||
|
||||
private String generateNonce() {
|
||||
return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
|
||||
}
|
||||
|
||||
private void handleResponse(CloseableHttpResponse response, String phone) throws IOException {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
String responseBody = EntityUtils.toString(response.getEntity());
|
||||
|
||||
log.info("UniSMS response status: {}, body: {}", statusCode, responseBody);
|
||||
|
||||
if (statusCode != 200) {
|
||||
throw new SendMessageException("HTTP request failed with status code: " + statusCode + ", response: " + responseBody);
|
||||
}
|
||||
|
||||
JsonNode jsonResponse = JsonUtil.fromJson(responseBody);
|
||||
String code = jsonResponse.get("code").asText();
|
||||
if (!SUCCESS_CODE.equals(code)) {
|
||||
String message = jsonResponse.get("message").asText();
|
||||
throw new SendMessageException(code + ":" + message);
|
||||
}
|
||||
|
||||
log.info("Successfully sent SMS to phone: {}", phone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return UNISMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkConfig() {
|
||||
if (config == null
|
||||
|| config.getAccessKeyId() == null
|
||||
|| config.getAccessKeyId().isBlank()
|
||||
|| config.getSignature() == null
|
||||
|| config.getSignature().isBlank()
|
||||
|| config.getTemplateId() == null
|
||||
|| config.getTemplateId().isBlank()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// HMAC mode requires additional check for accessKeySecret
|
||||
if ("hmac".equalsIgnoreCase(config.getAuthMode())
|
||||
&& (config.getAccessKeySecret() == null || config.getAccessKeySecret().isBlank())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.alert.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* General encryption utility class
|
||||
*/
|
||||
@Slf4j
|
||||
public class CryptoUtils {
|
||||
|
||||
private static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||
|
||||
private CryptoUtils() {}
|
||||
|
||||
/**
|
||||
* Calculate HMAC-SHA256 signature
|
||||
* @param key secret key
|
||||
* @param msg message to be signed
|
||||
* @return signed byte array
|
||||
*/
|
||||
public static byte[] hmac256(byte[] key, String msg) {
|
||||
try {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
|
||||
mac.init(secretKeySpec);
|
||||
return mac.doFinal(msg.getBytes(UTF8));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to calculate HMAC-SHA256: {}", e.getMessage());
|
||||
throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate SHA256 hash and convert to lowercase hexadecimal string
|
||||
* @param data data to be hashed
|
||||
* @return lowercase hexadecimal string
|
||||
*/
|
||||
public static String sha256Hex(String data) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
byte[] digest = md.digest(data.getBytes(UTF8));
|
||||
return DatatypeConverter.printHexBinary(digest).toLowerCase();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to calculate SHA256: {}", e.getMessage());
|
||||
throw new RuntimeException("Failed to calculate SHA256", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate HMAC-SHA256 signature and convert to Base64 string
|
||||
* @param key secret key
|
||||
* @param data data to be signed
|
||||
* @return Base64 encoded signature string
|
||||
*/
|
||||
public static String hmacSha256Base64(String key, String data) {
|
||||
byte[] hmacResult = hmac256(key.getBytes(UTF8), data);
|
||||
return Base64.getEncoder().encodeToString(hmacResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate HMAC-SHA256 signature and convert to lowercase hexadecimal string
|
||||
* @param key secret key
|
||||
* @param data data to be signed
|
||||
* @return lowercase hexadecimal string
|
||||
*/
|
||||
public static String hmacSha256Hex(String key, String data) {
|
||||
byte[] hmacResult = hmac256(key.getBytes(UTF8), data);
|
||||
return DatatypeConverter.printHexBinary(hmacResult).toLowerCase();
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.alert.util;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
/**
|
||||
* used to calculate the signature of the Tencent Cloud API.
|
||||
*/
|
||||
public class TencentCloudApiSignV3 {
|
||||
private static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||
|
||||
public static String calculateAuthorization(String secretId, String secretKey,
|
||||
String service, String host, String region,
|
||||
String action, String version, String payload) throws Exception {
|
||||
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
|
||||
|
||||
// Step 1: Construct the canonical request string
|
||||
String httpRequestMethod = "POST";
|
||||
String canonicalUri = "/";
|
||||
String canonicalQueryString = "";
|
||||
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n";
|
||||
String signedHeaders = "content-type;host";
|
||||
String hashedRequestPayload = sha256Hex(payload);
|
||||
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
|
||||
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
|
||||
|
||||
// Step 2: Construct the string to sign
|
||||
String algorithm = "TC3-HMAC-SHA256";
|
||||
String credentialScope = date + "/" + service + "/" + "tc3_request";
|
||||
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
|
||||
String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
|
||||
|
||||
// Step 3: Calculate the signature
|
||||
byte[] secretDate = hmac256(("TC3" + secretKey).getBytes(UTF8), date);
|
||||
byte[] secretService = hmac256(secretDate, service);
|
||||
byte[] secretSigning = hmac256(secretService, "tc3_request");
|
||||
String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
|
||||
|
||||
// Step 4: Construct the Authorization header
|
||||
return algorithm + " " + "Credential=" + secretId + "/" + credentialScope + ", "
|
||||
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
|
||||
}
|
||||
|
||||
public static byte[] hmac256(byte[] key, String msg) throws Exception {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
|
||||
mac.init(secretKeySpec);
|
||||
return mac.doFinal(msg.getBytes(UTF8));
|
||||
}
|
||||
|
||||
public static String sha256Hex(String s) throws Exception {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
byte[] d = md.digest(s.getBytes(UTF8));
|
||||
return DatatypeConverter.printHexBinary(d).toLowerCase();
|
||||
}
|
||||
}
|
||||
-2
@@ -223,9 +223,7 @@ public class KafkaCollectImpl extends AbstractCollect {
|
||||
|
||||
@Override
|
||||
public void preCheck(Metrics metrics) throws IllegalArgumentException {
|
||||
Assert.isTrue(metrics != null, "Metrics cannot be null");
|
||||
KafkaProtocol kafkaProtocol = metrics.getKclient();
|
||||
|
||||
// Ensure that metrics and kafkaProtocol are not null
|
||||
Assert.isTrue(metrics != null && kafkaProtocol != null, "Kafka collect must have kafkaProtocol params");
|
||||
// Ensure that host and port are not empty
|
||||
|
||||
+9
-8
@@ -42,7 +42,7 @@ public class KafkaCollectTest {
|
||||
@Test
|
||||
void preCheck() {
|
||||
// metrics is null
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
collect.preCheck(null);
|
||||
});
|
||||
|
||||
@@ -51,21 +51,22 @@ public class KafkaCollectTest {
|
||||
collect.preCheck(Metrics.builder().build());
|
||||
});
|
||||
|
||||
KafkaProtocol kafka = new KafkaProtocol();
|
||||
Metrics metric = Metrics.builder().kclient(kafka).build();
|
||||
// kafka srv host is null
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
collect.preCheck(metric);
|
||||
KafkaProtocol kafka = new KafkaProtocol();
|
||||
collect.preCheck(Metrics.builder().kclient(kafka).build());
|
||||
});
|
||||
|
||||
// kafka port is null
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
kafka.setHost("127.0.0.1");
|
||||
collect.preCheck(metric);
|
||||
KafkaProtocol kafka = KafkaProtocol.builder().host("127.0.0.1").build();
|
||||
collect.preCheck(Metrics.builder().kclient(kafka).build());
|
||||
});
|
||||
|
||||
// no exception throw
|
||||
assertDoesNotThrow(() -> {
|
||||
kafka.setPort("9092");
|
||||
collect.preCheck(metric);
|
||||
KafkaProtocol kafka = KafkaProtocol.builder().host("127.0.0.1").port("9092").build();
|
||||
collect.preCheck(Metrics.builder().kclient(kafka).build());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,6 @@ package org.apache.hertzbeat.common.constants;
|
||||
public interface SmsConstants {
|
||||
// Tencent cloud SMS
|
||||
String TENCENT = "tencent";
|
||||
|
||||
// Alibaba Cloud SMS
|
||||
String ALIBABA = "alibaba";
|
||||
|
||||
// UniSMS
|
||||
String UNISMS = "unisms";
|
||||
}
|
||||
|
||||
+4
-9
@@ -26,15 +26,10 @@ import lombok.Data;
|
||||
@Data
|
||||
public class SmsAlibabaConfig {
|
||||
|
||||
@NotBlank(message = "AccessKeyId cannot be empty")
|
||||
private String accessKeyId;
|
||||
@NotBlank(message = "SecretId cannot be empty")
|
||||
private String secretId;
|
||||
|
||||
@NotBlank(message = "AccessKeySecret cannot be empty")
|
||||
private String accessKeySecret;
|
||||
@NotBlank(message = "SecretKey cannot be empty")
|
||||
private String secretKey;
|
||||
|
||||
@NotBlank(message = "SignName cannot be empty")
|
||||
private String signName;
|
||||
|
||||
@NotBlank(message = "TemplateCode cannot be null")
|
||||
private String templateCode;
|
||||
}
|
||||
|
||||
-2
@@ -37,7 +37,5 @@ public class SmsNoticeSender {
|
||||
|
||||
private SmsAlibabaConfig alibaba;
|
||||
|
||||
private SmsUniSmsConfig unisms;
|
||||
|
||||
private boolean enable = true;
|
||||
}
|
||||
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.logging.log4j.core.config.plugins.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* UniSMS configuration
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SmsUniSmsConfig {
|
||||
/**
|
||||
* UniSMS access key id
|
||||
*/
|
||||
@NotBlank(message = "accessKeyId cannot be empty")
|
||||
private String accessKeyId;
|
||||
|
||||
/**
|
||||
* UniSMS access key secret, required for HMAC mode
|
||||
*/
|
||||
private String accessKeySecret;
|
||||
|
||||
/**
|
||||
* SMS signature
|
||||
*/
|
||||
@NotBlank(message = "signature cannot be null")
|
||||
private String signature;
|
||||
|
||||
/**
|
||||
* SMS template ID
|
||||
*/
|
||||
@NotBlank(message = "templateId cannot be null")
|
||||
private String templateId;
|
||||
|
||||
/**
|
||||
* Authentication mode: simple or hmac, default is simple
|
||||
*/
|
||||
@NotBlank(message = "authMode cannot be null")
|
||||
private String authMode = "simple";
|
||||
}
|
||||
@@ -204,7 +204,7 @@ alerter:
|
||||
inhibit:
|
||||
ttl: 14400000
|
||||
sms:
|
||||
enable: false
|
||||
enable: true
|
||||
type: tencent
|
||||
tencent:
|
||||
secret-id:
|
||||
@@ -213,18 +213,7 @@ alerter:
|
||||
sign-name:
|
||||
template-id:
|
||||
alibaba:
|
||||
access-key-id:
|
||||
access-key-secret:
|
||||
sign-name:
|
||||
template-code:
|
||||
unisms:
|
||||
# auth-mode: simple or hmac
|
||||
auth-mode: simple
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
# hmac mode need to fill in access-key-secret
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
app-id:
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -77,7 +77,7 @@ Hi HertzBeat PPMC,
|
||||
|
||||
This is a formal vote about inviting ${NEW_COMMITTER_NAME} as our community new committer.
|
||||
|
||||
Work list: https://github.com/apache/hertzbeat/commits?author=xxx
|
||||
Work list: https://github.com/apache/hertzbeat/commits?author=${NEW_COMMITTER_NAME}
|
||||
|
||||
Here is the list of ${NEW_COMMITTER_NAME}'s contributions in HertzBeat Community:
|
||||
|
||||
|
||||
@@ -8,76 +8,52 @@ This describes how to configure the SMS server, the number of built-in availabil
|
||||
|
||||
**Configuration file `application.yml` of `hertzbeat`**
|
||||
|
||||
Configuring the HertzBeat configuration file:
|
||||
### Configure the configuration file of HertzBeat
|
||||
|
||||
- Modify the configuration file located at `hertzbeat/config/application.yml`
|
||||
- **Docker Deployment:** ⚠️ When using a Docker container, the `application.yml` file must be mounted to the host machine
|
||||
- **Installation Package Deployment:** Extract the package and modify the configuration file located at `hertzbeat/config/application.yml`
|
||||
Modify the configuration file located at `hertzbeat/config/application.yml`
|
||||
Note ⚠️The docker container method needs to mount the application.yml file to the local host
|
||||
The installation package can be decompressed and modified in `hertzbeat/config/application.yml`
|
||||
|
||||
## 1. Configuring the SMS Sending Service
|
||||
1. Configure the SMS sending server
|
||||
|
||||
Only when you successfully configure your own SMS service will the alert SMS triggered within the monitoring system be sent correctly.
|
||||
HertzBeat provides two ways to configure the SMS service: modifying the `application.yml` configuration file directly or configuring it through the HertzBeat frontend interface (Settings > Message Server Setting).
|
||||
> Only when your own SMS server is successfully configured, the alarm SMS triggered in the monitoring tool will be sent normally.
|
||||
|
||||
> ⚠️ Note: Only one method can be effective at a time. If both methods are configured and enabled, HertzBeat will prioritize the SMS service configured in the frontend interface.
|
||||
Add the following Tencent platform SMS server configuration in `application.yml` (parameters need to be replaced with your SMS server configuration)
|
||||
|
||||
### 1.1 Tencent Cloud SMS Configuration
|
||||
```yaml
|
||||
common:
|
||||
sms:
|
||||
tencent:
|
||||
secret-id: AKIDbQ4VhdMr89wDedFrIcgU2PaaMvOuBCzY
|
||||
secret-key: PaXGl0ziY9UcWFjUyiFlCPMr77rLkJYlyA
|
||||
app-id: 1435441637
|
||||
sign-name: XX Technology
|
||||
template-id: 1343434
|
||||
```
|
||||
|
||||
Add the following Tencent Cloud SMS server configuration to `application.yml` (replace parameters with your own SMS server configuration):
|
||||
2. Configure alarm custom parameters
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # Whether to enable
|
||||
type: tencent # SMS provider type, supports "tencent"
|
||||
tencent: # Tencent Cloud SMS configuration
|
||||
secret-id: AKIDbQ4VhdMr89wDedFrIcgU2PaaMvOuBCzY
|
||||
secret-key: PaXGl0ziY9UcWFjUyiFlCPMr77rLkJYlyA
|
||||
app-id: 1435441637
|
||||
sign-name: HertzBeat
|
||||
template-id: 1343434
|
||||
```
|
||||
```yaml
|
||||
alerter:
|
||||
# Custom console address
|
||||
console-url: https://console.tancloud.io
|
||||
```
|
||||
|
||||
1. Create a signature (sign-name) in Tencent Cloud SMS
|
||||

|
||||
3. Use external redis instead of memory to store real-time metric data
|
||||
|
||||
2. Create a message template (template-id) in Tencent Cloud SMS
|
||||
> By default, the real-time data of our metrics is stored in memory, which can be configured as follows to use redis instead of memory storage.
|
||||
|
||||
```text
|
||||
Monitor: {1}, Alert Level: {2}. Content: {3}
|
||||
```
|
||||
Note ⚠️ `memory.enabled: false, redis.enabled: true`
|
||||
|
||||

|
||||
|
||||
3. Create an application (app-id) in Tencent Cloud SMS
|
||||

|
||||
|
||||
4. Obtain Tencent Cloud Access Management credentials (secret-id, secret-key)
|
||||

|
||||
|
||||
## 2. Configuring Custom Alert Parameters
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
# Custom console URL
|
||||
console-url: https://console.tancloud.io
|
||||
```
|
||||
|
||||
## 3. Using an External Redis Instead of In-Memory Storage for Real-Time Metric Data
|
||||
|
||||
> By default, real-time metric data is stored in memory. You can configure Redis as a replacement using the settings below.
|
||||
|
||||
⚠️ Note: Set `memory.enabled: false, redis.enabled: true`
|
||||
|
||||
```yaml
|
||||
warehouse:
|
||||
store:
|
||||
memory:
|
||||
enabled: false
|
||||
init-size: 1024
|
||||
redis:
|
||||
enabled: true
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
password: 123456
|
||||
```
|
||||
```yaml
|
||||
warehouse:
|
||||
store:
|
||||
memory:
|
||||
enabled: false
|
||||
init-size: 1024
|
||||
redis:
|
||||
enabled: true
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
password: 123456
|
||||
```
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ Hi HertzBeat PPMC,
|
||||
|
||||
This is a formal vote about inviting ${NEW_COMMITTER_NAME} as our community new committer.
|
||||
|
||||
Work list: https://github.com/apache/hertzbeat/commits?author=xxx
|
||||
Work list: https://github.com/apache/hertzbeat/commits?author=${NEW_COMMITTER_NAME}
|
||||
|
||||
Here is the list of ${NEW_COMMITTER_NAME}'s contributions in HertzBeat Community:
|
||||
|
||||
|
||||
@@ -4,79 +4,73 @@ title: 常见参数配置
|
||||
sidebar_label: 常见参数配置
|
||||
---
|
||||
|
||||
这里描述了如何配置短信服务,内置可用性告警触发次数等。
|
||||
这里描述了如果配置短信服务器,内置可用性告警触发次数等。
|
||||
|
||||
**`hertzbeat`的配置文件`application.yml`**
|
||||
|
||||
配置HertzBeat的配置文件
|
||||
### 配置HertzBeat的配置文件
|
||||
|
||||
- 修改位于 `hertzbeat/config/application.yml` 的配置文件
|
||||
- **Docker部署:** ⚠️docker容器方式需要将 `application.yml` 文件挂载到主机本地
|
||||
- **安装包方式:** 解压修改位于 `hertzbeat/config/application.yml` 的配置文件即可
|
||||
修改位于 `hertzbeat/config/application.yml` 的配置文件
|
||||
注意⚠️docker容器方式需要将application.yml文件挂载到主机本地
|
||||
安装包方式解压修改位于 `hertzbeat/config/application.yml` 即可
|
||||
|
||||
## 1. 配置短信发送服务
|
||||
1. 配置短信发送服务器
|
||||
|
||||
只有成功配置了您自己的短信服务,监控系统内触发的告警短信才会正常发送。
|
||||
hertzbeat有两种方式配置短信服务,一种是直接修改`application.yml`配置文件,另一种是通过hertzbeat前端界面(系统设置 > 消息服务配置)配置。
|
||||
> 注意⚠️:两种方式配置的短信服务只能选择一种生效,当两种方式都配置并且开启时,hertzbeat将会优先使用前端界面配置的短信服务。
|
||||
> 只有成功配置了您自己的短信服务器,监控系统内触发的告警短信才会正常发送。
|
||||
|
||||
### 1.1 腾讯云短信配置
|
||||
在`application.yml`新增如下腾讯平台短信服务器配置(参数需替换为您的短信服务器配置)
|
||||
|
||||
在`application.yml`新增如下腾讯平台短信服务器配置(参数需替换为您的短信服务器配置)
|
||||
```yaml
|
||||
common:
|
||||
sms:
|
||||
tencent:
|
||||
secret-id: AKIDbQ4VhdMr89wDedFrIcgU2PaaMvOuBCzY
|
||||
secret-key: PaXGl0ziY9UcWFjUyiFlCPMr77rLkJYlyA
|
||||
app-id: 1435441637
|
||||
sign-name: 赫兹跳动
|
||||
template-id: 1343434
|
||||
```
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
sms:
|
||||
enable: true # 是否启用
|
||||
type: tencent # 短信服务商类型,支持tencent、
|
||||
tencent: # 腾讯云短信配置
|
||||
secret-id: AKIDbQ4VhdMr89wDedFrIcgU2PaaMvOuBCzY
|
||||
secret-key: PaXGl0ziY9UcWFjUyiFlCPMr77rLkJYlyA
|
||||
app-id: 1435441637
|
||||
sign-name: 赫兹跳动
|
||||
template-id: 1343434
|
||||
```
|
||||
1.1 腾讯云短信创建签名(sign-name)
|
||||

|
||||
|
||||
1. 腾讯云短信创建签名(sign-name)
|
||||

|
||||
1.2 腾讯云短信创建正文模板(template-id)
|
||||
|
||||
2. 腾讯云短信创建正文模板(template-id)
|
||||
```text
|
||||
监控:{1},告警级别:{2}。内容:{3}
|
||||
```
|
||||
|
||||
```text
|
||||
监控:{1},告警级别:{2}。内容:{3}
|
||||
```
|
||||

|
||||
|
||||

|
||||
1.3 腾讯云短信创建应用(app-id)
|
||||

|
||||
|
||||
3. 腾讯云短信创建应用(app-id)
|
||||

|
||||
1.4 腾讯云访问管理(secret-id、secret-key)
|
||||

|
||||
|
||||
4. 腾讯云访问管理(secret-id、secret-key)
|
||||

|
||||
2. 配置告警自定义参数
|
||||
|
||||
## 2. 配置告警自定义参数
|
||||
```yaml
|
||||
alerter:
|
||||
# 自定义控制台地址
|
||||
console-url: https://console.tancloud.io
|
||||
```
|
||||
|
||||
```yaml
|
||||
alerter:
|
||||
# 自定义控制台地址
|
||||
console-url: https://console.tancloud.io
|
||||
```
|
||||
3. 使用外置redis代替内存存储实时指标数据
|
||||
|
||||
## 3. 使用外置redis代替内存存储实时指标数据
|
||||
> 默认我们的指标实时数据存储在内存中,可以配置如下来使用redis代替内存存储。
|
||||
|
||||
> 默认我们的指标实时数据存储在内存中,可以配置如下来使用redis代替内存存储。
|
||||
注意⚠️ `memory.enabled: false, redis.enabled: true`
|
||||
|
||||
注意⚠️ `memory.enabled: false, redis.enabled: true`
|
||||
|
||||
```yaml
|
||||
warehouse:
|
||||
store:
|
||||
memory:
|
||||
enabled: false
|
||||
init-size: 1024
|
||||
redis:
|
||||
enabled: true
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
password: 123456
|
||||
```
|
||||
```yaml
|
||||
warehouse:
|
||||
store:
|
||||
memory:
|
||||
enabled: false
|
||||
init-size: 1024
|
||||
redis:
|
||||
enabled: true
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
password: 123456
|
||||
```
|
||||
|
||||
@@ -202,28 +202,6 @@ alerter:
|
||||
# alert inhibit ttl unit ms, default 14400000(4 hours)
|
||||
inhibit:
|
||||
ttl: 14400000
|
||||
sms:
|
||||
enable: false
|
||||
type: tencent
|
||||
tencent:
|
||||
secret-id:
|
||||
secret-key:
|
||||
app-id:
|
||||
sign-name:
|
||||
template-id:
|
||||
alibaba:
|
||||
access-key-id:
|
||||
access-key-secret:
|
||||
sign-name:
|
||||
template-code:
|
||||
unisms:
|
||||
# auth-mode: simple or hmac
|
||||
auth-mode: simple
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
# hmac mode need to fill in access-key-secret
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -169,28 +169,6 @@ alerter:
|
||||
# alert inhibit ttl unit ms, default 14400000(4 hours)
|
||||
inhibit:
|
||||
ttl: 14400000
|
||||
sms:
|
||||
enable: false
|
||||
type: tencent
|
||||
tencent:
|
||||
secret-id:
|
||||
secret-key:
|
||||
app-id:
|
||||
sign-name:
|
||||
template-id:
|
||||
alibaba:
|
||||
access-key-id:
|
||||
access-key-secret:
|
||||
sign-name:
|
||||
template-code:
|
||||
unisms:
|
||||
# auth-mode: simple or hmac
|
||||
auth-mode: simple
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
# hmac mode need to fill in access-key-secret
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -165,28 +165,6 @@ alerter:
|
||||
# alert inhibit ttl unit ms, default 14400000(4 hours)
|
||||
inhibit:
|
||||
ttl: 14400000
|
||||
sms:
|
||||
enable: false
|
||||
type: tencent
|
||||
tencent:
|
||||
secret-id:
|
||||
secret-key:
|
||||
app-id:
|
||||
sign-name:
|
||||
template-id:
|
||||
alibaba:
|
||||
access-key-id:
|
||||
access-key-secret:
|
||||
sign-name:
|
||||
template-code:
|
||||
unisms:
|
||||
# auth-mode: simple or hmac
|
||||
auth-mode: simple
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
# hmac mode need to fill in access-key-secret
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -163,28 +163,6 @@ alerter:
|
||||
# alert inhibit ttl unit ms, default 14400000(4 hours)
|
||||
inhibit:
|
||||
ttl: 14400000
|
||||
sms:
|
||||
enable: false
|
||||
type: tencent
|
||||
tencent:
|
||||
secret-id:
|
||||
secret-key:
|
||||
app-id:
|
||||
sign-name:
|
||||
template-id:
|
||||
alibaba:
|
||||
access-key-id:
|
||||
access-key-secret:
|
||||
sign-name:
|
||||
template-code:
|
||||
unisms:
|
||||
# auth-mode: simple or hmac
|
||||
auth-mode: simple
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
# hmac mode need to fill in access-key-secret
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -162,28 +162,6 @@ alerter:
|
||||
# alert inhibit ttl unit ms, default 14400000(4 hours)
|
||||
inhibit:
|
||||
ttl: 14400000
|
||||
sms:
|
||||
enable: false
|
||||
type: tencent
|
||||
tencent:
|
||||
secret-id:
|
||||
secret-key:
|
||||
app-id:
|
||||
sign-name:
|
||||
template-id:
|
||||
alibaba:
|
||||
access-key-id:
|
||||
access-key-secret:
|
||||
sign-name:
|
||||
template-code:
|
||||
unisms:
|
||||
# auth-mode: simple or hmac
|
||||
auth-mode: simple
|
||||
access-key-id: YOUR_ACCESS_KEY_ID
|
||||
# hmac mode need to fill in access-key-secret
|
||||
access-key-secret: YOUR_ACCESS_KEY_SECRET
|
||||
signature: YOUR_SMS_SIGNATURE
|
||||
template-id: YOUR_TEMPLATE_ID
|
||||
|
||||
scheduler:
|
||||
server:
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
*/
|
||||
|
||||
export class AlibabaSmsConfig {
|
||||
accessKeyId!: string;
|
||||
accessKeySecret!: string;
|
||||
secretId!: string;
|
||||
secretKey!: string;
|
||||
signName!: string;
|
||||
templateCode!: string;
|
||||
appId!: string;
|
||||
templateId!: string;
|
||||
}
|
||||
|
||||
@@ -19,16 +19,13 @@
|
||||
|
||||
import { AlibabaSmsConfig } from './AlibabaSmsConfig';
|
||||
import { TencentSmsConfig } from './TencentSmsConfig';
|
||||
import { UniSmsConfig } from './UniSmsConfig';
|
||||
import { SmsType } from './enums/sms-type.enum';
|
||||
|
||||
export class SmsNoticeSender {
|
||||
id!: number;
|
||||
type: SmsType = SmsType.TENCENT;
|
||||
tencent: TencentSmsConfig = new TencentSmsConfig();
|
||||
alibaba: AlibabaSmsConfig = new AlibabaSmsConfig();
|
||||
unisms: UniSmsConfig = new UniSmsConfig();
|
||||
enable: boolean = false;
|
||||
type!: string;
|
||||
tencent!: TencentSmsConfig;
|
||||
alibaba!: AlibabaSmsConfig;
|
||||
enable!: boolean;
|
||||
creator!: string;
|
||||
modifier!: string;
|
||||
gmtCreate!: number;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export class UniSmsConfig {
|
||||
accessKeyId!: string;
|
||||
accessKeySecret!: string;
|
||||
signature!: string;
|
||||
authMode!: string;
|
||||
templateId!: string;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export enum SmsType {
|
||||
TENCENT = 'tencent',
|
||||
ALIBABA = 'alibaba',
|
||||
UNISMS = 'unisms'
|
||||
}
|
||||
|
||||
export enum UniSmsAuthMode {
|
||||
HMAC = 'hmac',
|
||||
SIMPLE = 'simple'
|
||||
}
|
||||
@@ -38,6 +38,22 @@
|
||||
border-radius: 6px;
|
||||
padding: 4px 11px 4px 40px;
|
||||
}
|
||||
|
||||
.ant-input-prefix {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 16px;
|
||||
margin-right: 8px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper {
|
||||
border-radius: 6px;
|
||||
|
||||
&:hover, &:focus {
|
||||
border-color: #40a9ff;
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,59 +390,6 @@
|
||||
:host {
|
||||
.alert-card {
|
||||
background-color: @common-background-color-dark;
|
||||
.alert-header {
|
||||
.alert-info {
|
||||
.alert-meta-info {
|
||||
color: rgb(214, 214, 214);
|
||||
}
|
||||
}
|
||||
}
|
||||
.alert-details {
|
||||
::ng-deep {
|
||||
.ant-collapse {
|
||||
.ant-collapse-item {
|
||||
.ant-collapse-header {
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.ant-collapse-extra {
|
||||
color: rgb(236, 236, 236);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.detail-section {
|
||||
.section-title {
|
||||
color: #cdcdcd;
|
||||
}
|
||||
.alert-count {
|
||||
color: #ececec;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-annotations {
|
||||
.annotation-item {
|
||||
.annotation-key {
|
||||
color: #dfdede;
|
||||
}
|
||||
.annotation-value {
|
||||
color: #e3e3e3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.time-info {
|
||||
.time-item {
|
||||
.time-label {
|
||||
color: #dfdede;
|
||||
}
|
||||
.time-value {
|
||||
color: #e3e3e3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,12 +54,8 @@
|
||||
groupStyle="width: 250px;"
|
||||
[placeholder]="'alert.group-converge.name' | i18n"
|
||||
[(value)]="search"
|
||||
(keydown.enter)="onFilterChange()"
|
||||
(cleared)="onFilterChange()"
|
||||
(valueChange)="onFilterChange()"
|
||||
/>
|
||||
<button nz-button nzType="primary" (click)="onFilterChange()" class="mobile-hide">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
|
||||
@@ -81,13 +77,12 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th nzAlign="center" nzLeft nzWidth="3%" [(nzChecked)]="checkedAll" (nzCheckedChange)="onAllChecked($event)"></th>
|
||||
<th nzAlign="center" nzWidth="14%">{{ 'alert.group-converge.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="12%">{{ 'alert.group-converge.group-labels' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.group-converge.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="20%">{{ 'alert.group-converge.group-labels' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="10%">{{ 'alert.group-converge.group-wait' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="10%">{{ 'alert.group-converge.group-interval' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="10%">{{ 'alert.group-converge.repeat-interval' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="10%" nzRight>{{ 'common.enable' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="14%">{{ 'common.edit-time' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="8%" nzRight>{{ 'alert.group-converge.enable' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="12%" nzRight>{{ 'common.edit' | i18n }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -106,7 +101,6 @@
|
||||
<td nzAlign="center" nzRight>
|
||||
<nz-switch [(ngModel)]="data.enable" (ngModelChange)="updateGroupConverge(data)" name="enable"></nz-switch>
|
||||
</td>
|
||||
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date : 'YYYY-MM-dd HH:mm:ss' }}</td>
|
||||
<td nzAlign="center" nzRight>
|
||||
<div class="actions">
|
||||
<button
|
||||
|
||||
@@ -54,12 +54,8 @@
|
||||
groupStyle="width: 250px;"
|
||||
[placeholder]="'alert.inhibit.name' | i18n"
|
||||
[(value)]="search"
|
||||
(keydown.enter)="onFilterChange()"
|
||||
(cleared)="onFilterChange()"
|
||||
(valueChange)="onFilterChange()"
|
||||
/>
|
||||
<button nz-button nzType="primary" (click)="onFilterChange()" class="mobile-hide">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
|
||||
@@ -82,11 +78,10 @@
|
||||
<tr>
|
||||
<th nzAlign="center" nzLeft nzWidth="3%" [(nzChecked)]="checkedAll" (nzCheckedChange)="onAllChecked($event)"></th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.inhibit.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="18%">{{ 'alert.inhibit.source_labels' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="18%">{{ 'alert.inhibit.target_labels' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="20%">{{ 'alert.inhibit.source_labels' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="20%">{{ 'alert.inhibit.target_labels' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.inhibit.equal_labels' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="12%" nzRight>{{ 'common.enable' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="14%">{{ 'common.edit-time' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="8%" nzRight>{{ 'common.enable' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="12%" nzRight>{{ 'common.edit' | i18n }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -106,7 +101,6 @@
|
||||
<td nzAlign="center" nzRight>
|
||||
<nz-switch [(ngModel)]="data.enable" (ngModelChange)="updateInhibit(data)" name="enable"></nz-switch>
|
||||
</td>
|
||||
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date : 'YYYY-MM-dd HH:mm:ss' }}</td>
|
||||
<td nzAlign="center" nzRight>
|
||||
<div class="actions">
|
||||
<button nz-button nzType="primary" (click)="editInhibit(data.id)" nz-tooltip [nzTooltipTitle]="'alert.inhibit.edit' | i18n">
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
{{ 'common.button.copy' | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
<div style="padding: 12px; border: 1px solid; border-radius: 4px; word-wrap: break-word">
|
||||
<div style="padding: 12px; border: 1px solid #d9d9d9; border-radius: 4px; background-color: #f5f5f5; word-wrap: break-word">
|
||||
{{ token }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+12
-25
@@ -33,12 +33,8 @@
|
||||
groupStyle="width: 250px;"
|
||||
[placeholder]="'alert.notice.receiver.people.name' | i18n"
|
||||
[(value)]="name"
|
||||
(keydown.enter)="onSearch()"
|
||||
(cleared)="onSearch()"
|
||||
(valueChange)="onSearch()"
|
||||
/>
|
||||
<button nz-button nzType="primary" (click)="onSearch()" class="mobile-hide">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
<nz-table
|
||||
@@ -59,9 +55,9 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.receiver.people' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.receiver.type' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="25%">{{ 'alert.notice.receiver.setting' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'common.edit-time' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="20%">{{ 'alert.notice.receiver.type' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="20%">{{ 'alert.notice.receiver.setting' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="20%">{{ 'common.edit-time' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%" nzRight>{{ 'common.edit' | i18n }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -156,24 +152,15 @@
|
||||
>
|
||||
<i nz-icon nzTheme="outline" nzType="edit"></i>
|
||||
</button>
|
||||
<button nz-button nz-dropdown [nzDropdownMenu]="more_menu">
|
||||
<span nz-icon nzType="ellipsis"></span>
|
||||
<button
|
||||
(click)="onDeleteOneNoticeReceiver(data.id)"
|
||||
[nzTooltipTitle]="'alert.notice.receiver.delete' | i18n"
|
||||
nz-button
|
||||
nz-tooltip
|
||||
nzDanger
|
||||
>
|
||||
<i nz-icon nzTheme="outline" nzType="delete"></i>
|
||||
</button>
|
||||
<nz-dropdown-menu #more_menu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
<li nz-menu-item>
|
||||
<button
|
||||
(click)="onDeleteOneNoticeReceiver(data.id)"
|
||||
[nzTooltipTitle]="'alert.notice.receiver.delete' | i18n"
|
||||
nz-button
|
||||
nz-tooltip
|
||||
nzDanger
|
||||
>
|
||||
<i nz-icon nzTheme="outline" nzType="delete"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nz-dropdown-menu>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
+14
-27
@@ -33,12 +33,8 @@
|
||||
groupStyle="width: 250px;"
|
||||
[placeholder]="'alert.notice.rule.name' | i18n"
|
||||
[(value)]="name"
|
||||
(keydown.enter)="onSearch()"
|
||||
(cleared)="onSearch()"
|
||||
(valueChange)="onSearch()"
|
||||
/>
|
||||
<button nz-button nzType="primary" (click)="onSearch()" class="mobile-hide">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
<nz-table
|
||||
@@ -58,13 +54,13 @@
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th nzAlign="center" nzWidth="12%">{{ 'alert.notice.rule.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="12%">{{ 'alert.notice.receiver.people' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="10%">{{ 'alert.notice.template.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.rule.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.receiver.people' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.template.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="10%">{{ 'alert.notice.rule.all' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="10%">{{ 'common.enable' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="14%">{{ 'common.edit-time' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="10%" nzRight>{{ 'common.edit' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="20%">{{ 'common.edit-time' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%" nzRight>{{ 'common.edit' | i18n }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -99,24 +95,15 @@
|
||||
>
|
||||
<i nz-icon nzTheme="outline" nzType="edit"></i>
|
||||
</button>
|
||||
<button nz-button nz-dropdown [nzDropdownMenu]="more_menu">
|
||||
<span nz-icon nzType="ellipsis"></span>
|
||||
<button
|
||||
(click)="onDeleteOneNoticeRule(data.id)"
|
||||
[nzTooltipTitle]="'alert.notice.rule.delete' | i18n"
|
||||
nz-button
|
||||
nz-tooltip
|
||||
nzDanger
|
||||
>
|
||||
<i nz-icon nzTheme="outline" nzType="delete"></i>
|
||||
</button>
|
||||
<nz-dropdown-menu #more_menu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
<li nz-menu-item>
|
||||
<button
|
||||
(click)="onDeleteOneNoticeRule(data.id)"
|
||||
[nzTooltipTitle]="'alert.notice.rule.delete' | i18n"
|
||||
nz-button
|
||||
nz-tooltip
|
||||
nzDanger
|
||||
>
|
||||
<i nz-icon nzTheme="outline" nzType="delete"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nz-dropdown-menu>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
+3
-7
@@ -36,12 +36,8 @@
|
||||
groupStyle="width: 250px;"
|
||||
[placeholder]="'alert.notice.template.name' | i18n"
|
||||
[(value)]="name"
|
||||
(keydown.enter)="onSearch()"
|
||||
(cleared)="onSearch()"
|
||||
(valueChange)="onSearch()"
|
||||
/>
|
||||
<button nz-button nzType="primary" (click)="onSearch()" class="mobile-hide">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
<nz-table
|
||||
@@ -61,7 +57,7 @@
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th nzAlign="center" nzWidth="20%">{{ 'alert.notice.template.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="25%">{{ 'alert.notice.template.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.template.type' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.template.preset' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="20%">{{ 'common.edit-time' | i18n }}</th>
|
||||
@@ -248,7 +244,7 @@
|
||||
[(ngModel)]="template.content"
|
||||
id="template_content_example"
|
||||
name="template_content"
|
||||
class="textarea"
|
||||
style="white-space: nowrap; overflow: scroll; width: 100%; height: 200px"
|
||||
type="textarea"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
@import "~src/styles/theme";
|
||||
|
||||
.textarea {
|
||||
white-space: nowrap;
|
||||
overflow: scroll;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
background-color: #c6bfbf;
|
||||
}
|
||||
|
||||
@@ -72,9 +72,6 @@
|
||||
(keydown.enter)="onFilterChange()"
|
||||
(cleared)="onFilterChange()"
|
||||
/>
|
||||
<button nz-button nzType="primary" (click)="onFilterChange()">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
|
||||
@@ -96,13 +93,12 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th nzAlign="center" nzLeft nzWidth="3%" [(nzChecked)]="checkedAll" (nzCheckedChange)="onAllChecked($event)"></th>
|
||||
<th nzAlign="center" nzWidth="12%">{{ 'alert.setting.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="10%">{{ 'alert.setting.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="8%">{{ 'alert.setting.type' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.setting.expr' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'alert.setting.template' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="15%">{{ 'label.bind' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="8%" nzRight>{{ 'common.enable' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="14%">{{ 'common.edit-time' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="24%">{{ 'alert.setting.expr' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="20%">{{ 'alert.setting.template' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="8%">{{ 'label.bind' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="8%" nzRight>{{ 'alert.setting.enable' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="8%" nzRight>{{ 'common.edit' | i18n }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -120,19 +116,16 @@
|
||||
<span>{{ 'alert.setting.type.periodic' | i18n }}</span>
|
||||
</nz-tag>
|
||||
</td>
|
||||
<td nzAlign="center" nzEllipsis nz-tooltip [nzTooltipTitle]="data.expr">
|
||||
<td nzAlign="center">
|
||||
<span>{{ data.expr }}</span>
|
||||
</td>
|
||||
<td nzAlign="center" nzEllipsis nz-tooltip [nzTooltipTitle]="data.template">
|
||||
<span>{{ data.template }}</span>
|
||||
</td>
|
||||
<td nzAlign="center">{{ data.template }}</td>
|
||||
<td nzAlign="center">
|
||||
<nz-tag *ngFor="let item of data.labels | keyvalue">{{ item.key }}:{{ item.value }}</nz-tag>
|
||||
</td>
|
||||
<td nzAlign="center" nzRight>
|
||||
<nz-switch [(ngModel)]="data.enable" (ngModelChange)="updateAlertDefine(data)" name="enable"></nz-switch>
|
||||
</td>
|
||||
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date : 'YYYY-MM-dd HH:mm:ss' }}</td>
|
||||
<td nzAlign="center" nzRight>
|
||||
<div class="actions">
|
||||
<button
|
||||
@@ -292,7 +285,12 @@
|
||||
<nz-form-item *ngIf="define.type == 'realtime' && cascadeValues.length > 0 && cascadeValues[1] !== 'availability' && !isExpr">
|
||||
<nz-form-label [nzSpan]="7" [nzNoColon]="true"></nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n" [nzValidateStatus]="qbFormCtrl">
|
||||
<ngx-query-builder [classNames]="qbClassNames" [config]="qbConfig" [formControl]="qbFormCtrl" [ngStyle]="{ borderRadius: '4px' }">
|
||||
<ngx-query-builder
|
||||
[classNames]="qbClassNames"
|
||||
[config]="qbConfig"
|
||||
[formControl]="qbFormCtrl"
|
||||
[ngStyle]="{ background: 'ghostwhite', borderRadius: '4px' }"
|
||||
>
|
||||
<ng-container *querySwitchGroup="let rule; let onChange = onChange">
|
||||
<nz-radio-group
|
||||
style="white-space: nowrap"
|
||||
|
||||
@@ -246,7 +246,8 @@
|
||||
gap: 10px;
|
||||
margin-bottom: 16px;
|
||||
padding: 12px;
|
||||
border: 1px dashed fade(@primary-color, 30%);
|
||||
background: #fafafa;
|
||||
border: 1px dashed @border-color;
|
||||
border-radius: 6px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -257,6 +258,7 @@
|
||||
.draggable-tag {
|
||||
padding: 8px 12px;
|
||||
min-width: 140px;
|
||||
background: #f0f5ff;
|
||||
border: 1px solid fade(@primary-color, 30%);
|
||||
border-radius: 4px;
|
||||
cursor: move;
|
||||
|
||||
@@ -54,12 +54,8 @@
|
||||
groupStyle="width: 250px;"
|
||||
[placeholder]="'alert.silence.name' | i18n"
|
||||
[(value)]="search"
|
||||
(keydown.enter)="onFilterChange()"
|
||||
(cleared)="onFilterChange()"
|
||||
(valueChange)="onFilterChange()"
|
||||
/>
|
||||
<button nz-button nzType="primary" (click)="onFilterChange()" class="mobile-hide">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
|
||||
@@ -81,12 +77,11 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th nzAlign="center" nzLeft nzWidth="3%" [(nzChecked)]="checkedAll" (nzCheckedChange)="onAllChecked($event)"></th>
|
||||
<th nzAlign="center" nzWidth="14%">{{ 'alert.silence.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="12%">{{ 'alert.silence.type' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="12%">{{ 'alert.silence.times' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="12%" nzRight>{{ 'common.enable' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="14%">{{ 'common.edit-time' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="12%" nzRight>{{ 'common.edit' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="7%">{{ 'alert.silence.name' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="7%">{{ 'alert.silence.type' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="10%">{{ 'alert.silence.times' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="3%" nzRight>{{ 'alert.silence.enable' | i18n }}</th>
|
||||
<th nzAlign="center" nzWidth="5%" nzRight>{{ 'common.edit' | i18n }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -114,7 +109,6 @@
|
||||
<td nzAlign="center" nzRight>
|
||||
<nz-switch [(ngModel)]="data.enable" (ngModelChange)="updateAlertSilence(data)" name="enable"></nz-switch>
|
||||
</td>
|
||||
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date : 'YYYY-MM-dd HH:mm:ss' }}</td>
|
||||
<td nzAlign="center" nzRight>
|
||||
<div class="actions">
|
||||
<button
|
||||
|
||||
@@ -122,20 +122,15 @@
|
||||
class="mobile-hide"
|
||||
[placeholder]="'monitor.search.label' | i18n"
|
||||
[(value)]="labels"
|
||||
(keydown.enter)="onFilterSearchMonitors()"
|
||||
(cleared)="onFilterSearchMonitors()"
|
||||
(valueChange)="onTagChanged()"
|
||||
/>
|
||||
<app-multi-func-input
|
||||
groupStyle="width: 180px;"
|
||||
class="mobile-hide"
|
||||
[placeholder]="'monitor.search.placeholder' | i18n"
|
||||
[(value)]="filterContent"
|
||||
(keydown.enter)="onFilterSearchMonitors()"
|
||||
(cleared)="onFilterSearchMonitors()"
|
||||
(valueChange)="onFilterSearchMonitors()"
|
||||
/>
|
||||
<button class="mobile-hide" nz-button nzType="primary" (click)="onFilterSearchMonitors()">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
|
||||
@@ -228,7 +223,13 @@
|
||||
<nz-dropdown-menu #more_menu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
<li nz-menu-item>
|
||||
<button nz-button (click)="onEditOneMonitor(data.id)" nz-tooltip [nzTooltipTitle]="'monitor.edit-monitor' | i18n">
|
||||
<button
|
||||
nz-button
|
||||
nzType="primary"
|
||||
(click)="onEditOneMonitor(data.id)"
|
||||
nz-tooltip
|
||||
[nzTooltipTitle]="'monitor.edit-monitor' | i18n"
|
||||
>
|
||||
<i nz-icon nzType="edit" nzTheme="outline"></i>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
@@ -120,6 +120,14 @@ export class MonitorListComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
onTagChanged(): void {
|
||||
this.router.navigate([], {
|
||||
relativeTo: this.route,
|
||||
queryParams: { ...this.route.snapshot.queryParams, tag: this.labels },
|
||||
queryParamsHandling: 'merge'
|
||||
});
|
||||
}
|
||||
|
||||
onFilterSearchMonitors() {
|
||||
this.tableLoading = true;
|
||||
this.pageIndex = 1;
|
||||
|
||||
@@ -68,12 +68,8 @@
|
||||
groupStyle="width: 250px;"
|
||||
[placeholder]="'collector.name' | i18n"
|
||||
[(value)]="search"
|
||||
(keydown.enter)="loadCollectorsTable()"
|
||||
(cleared)="loadCollectorsTable()"
|
||||
(valueChange)="loadCollectorsTable()"
|
||||
/>
|
||||
<button nz-button nzType="primary" (click)="loadCollectorsTable()" class="mobile-hide">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
|
||||
@@ -171,25 +167,16 @@
|
||||
>
|
||||
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
|
||||
</button>
|
||||
<button nz-button nz-dropdown [nzDropdownMenu]="more_menu">
|
||||
<span nz-icon nzType="ellipsis"></span>
|
||||
<button
|
||||
[disabled]="data.collector.name == 'main-default-collector'"
|
||||
nz-button
|
||||
nzDanger
|
||||
(click)="onDeleteOneCollector(data.collector.name)"
|
||||
nz-tooltip
|
||||
[nzTooltipTitle]="'collector.delete' | i18n"
|
||||
>
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
</button>
|
||||
<nz-dropdown-menu #more_menu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
<li nz-menu-item>
|
||||
<button
|
||||
[disabled]="data.collector.name == 'main-default-collector'"
|
||||
nz-button
|
||||
nzDanger
|
||||
(click)="onDeleteOneCollector(data.collector.name)"
|
||||
nz-tooltip
|
||||
[nzTooltipTitle]="'collector.delete' | i18n"
|
||||
>
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nz-dropdown-menu>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -55,12 +55,8 @@
|
||||
groupStyle="width: 250px;"
|
||||
[placeholder]="'plugin.search' | i18n"
|
||||
[(value)]="search"
|
||||
(keydown.enter)="loadPluginsTable()"
|
||||
(cleared)="loadPluginsTable()"
|
||||
(valueChange)="loadPluginsTable()"
|
||||
/>
|
||||
<button nz-button nzType="primary" (click)="loadPluginsTable()" class="mobile-hide">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
|
||||
@@ -114,18 +110,9 @@
|
||||
>
|
||||
<i nz-icon nzType="edit" nzTheme="outline"></i>
|
||||
</button>
|
||||
<button nz-button nz-dropdown [nzDropdownMenu]="more_menu">
|
||||
<span nz-icon nzType="ellipsis"></span>
|
||||
<button nz-button nzDanger (click)="onDeleteOnePlugin(data.id)" nz-tooltip [nzTooltipTitle]="'plugin.delete' | i18n">
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
</button>
|
||||
<nz-dropdown-menu #more_menu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
<li nz-menu-item>
|
||||
<button nz-button nzDanger (click)="onDeleteOnePlugin(data.id)" nz-tooltip [nzTooltipTitle]="'plugin.delete' | i18n">
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nz-dropdown-menu>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
+31
-156
@@ -47,34 +47,25 @@
|
||||
<ng-template #smsDesc>
|
||||
{{ 'alert.notice.sender.sms.type' | i18n }}: {{ 'alert.notice.sender.sms.type.' + smsNoticeSender.type | i18n }}
|
||||
<br />
|
||||
<ng-container [ngSwitch]="smsNoticeSender.type">
|
||||
<!-- Tencent SMS -->
|
||||
<ng-container *ngSwitchCase="SmsType.TENCENT">
|
||||
{{ 'alert.notice.sender.sms.tencent.appId' | i18n }}: {{ smsNoticeSender.tencent.appId }}
|
||||
<br />
|
||||
{{ 'alert.notice.sender.sms.tencent.signName' | i18n }}: {{ smsNoticeSender.tencent.signName }}
|
||||
<br />
|
||||
{{ 'alert.notice.sender.sms.tencent.templateId' | i18n }}: {{ smsNoticeSender.tencent.templateId }}
|
||||
</ng-container>
|
||||
|
||||
<!-- Alibaba SMS -->
|
||||
<ng-container *ngSwitchCase="SmsType.ALIBABA">
|
||||
{{ 'alert.notice.sender.sms.alibaba.signName' | i18n }}: {{ smsNoticeSender.alibaba.signName }}
|
||||
<br />
|
||||
{{ 'alert.notice.sender.sms.alibaba.templateCode' | i18n }}: {{ smsNoticeSender.alibaba.templateCode }}
|
||||
</ng-container>
|
||||
|
||||
<!-- UniSMS -->
|
||||
<ng-container *ngSwitchCase="SmsType.UNISMS">
|
||||
{{ 'alert.notice.sender.sms.unisms.signature' | i18n }}: {{ smsNoticeSender.unisms.signature }}
|
||||
<br />
|
||||
{{ 'alert.notice.sender.sms.unisms.templateId' | i18n }}: {{ smsNoticeSender.unisms.templateId }}
|
||||
<br />
|
||||
{{ 'alert.notice.sender.sms.unisms.authMode' | i18n }}: {{ smsNoticeSender.unisms.authMode }}
|
||||
</ng-container>
|
||||
<ng-container *ngIf="smsNoticeSender.type === 'tencent'">
|
||||
{{ 'alert.notice.sender.sms.tencent.secretId' | i18n }}: {{ smsNoticeSender.tencent.secretId }}
|
||||
<br />
|
||||
</ng-container>
|
||||
<ng-container *ngIf="smsNoticeSender.type === 'tencent'">
|
||||
{{ 'alert.notice.sender.sms.tencent.secretKey' | i18n }}: {{ smsNoticeSender.tencent.secretKey }}
|
||||
<br />
|
||||
</ng-container>
|
||||
<ng-container *ngIf="smsNoticeSender.type === 'tencent'">
|
||||
{{ 'alert.notice.sender.sms.tencent.signName' | i18n }}: {{ smsNoticeSender.tencent.signName }}
|
||||
<br />
|
||||
</ng-container>
|
||||
<ng-container *ngIf="smsNoticeSender.type === 'tencent'">
|
||||
{{ 'alert.notice.sender.sms.tencent.appId' | i18n }}: {{ smsNoticeSender.tencent.appId }}
|
||||
<br />
|
||||
</ng-container>
|
||||
<ng-container *ngIf="smsNoticeSender.type === 'tencent'">
|
||||
{{ 'alert.notice.sender.sms.tencent.templateId' | i18n }}: {{ smsNoticeSender.tencent.templateId }}
|
||||
</ng-container>
|
||||
<br />
|
||||
{{ 'common.enable' | i18n }}: {{ smsNoticeSender.enable ? ('common.yes' | i18n) : ('common.no' | i18n) }}
|
||||
</ng-template>
|
||||
</nz-list-item-meta>
|
||||
</nz-list-item>
|
||||
@@ -154,28 +145,27 @@
|
||||
<nz-form-item>
|
||||
<nz-form-label nzSpan="7" nzRequired="true">{{ 'alert.notice.sender.sms.type' | i18n }}</nz-form-label>
|
||||
<nz-form-control nzSpan="12">
|
||||
<nz-select [(ngModel)]="smsType" name="type" id="type" (ngModelChange)="onSmsTypeChange($event)">
|
||||
<nz-option [nzValue]="SmsType.TENCENT" nzLabel="{{ 'alert.notice.sender.sms.type.tencent' | i18n }}"></nz-option>
|
||||
<nz-option [nzValue]="SmsType.ALIBABA" nzLabel="{{ 'alert.notice.sender.sms.type.alibaba' | i18n }}"></nz-option>
|
||||
<nz-option [nzValue]="SmsType.UNISMS" nzLabel="{{ 'alert.notice.sender.sms.type.unisms' | i18n }}"></nz-option>
|
||||
<nz-select [(ngModel)]="smsType" name="type" id="type" (ngModelChange)="onSmsTypeChange(smsType)">
|
||||
<nz-option nzValue="tencent" nzLabel="{{ 'alert.notice.sender.sms.type.tencent' | i18n }}"></nz-option>
|
||||
<nz-option nzValue="alibaba" nzLabel="{{ 'alert.notice.sender.sms.type.alibaba' | i18n }}"></nz-option>
|
||||
</nz-select>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<ng-container *ngIf="smsType === SmsType.TENCENT">
|
||||
<ng-container *ngIf="smsType === 'tencent'">
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="secretId" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.tencent.secretId' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-label [nzSpan]="7" nzFor="secretId" nzRequired="true">{{
|
||||
'alert.notice.sender.sms.tencent.secretId' | i18n
|
||||
}}</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input [(ngModel)]="smsNoticeSender.tencent.secretId" nz-input required name="secretId" type="password" id="secretId" />
|
||||
<input [(ngModel)]="smsNoticeSender.tencent.secretId" nz-input required name="secretId" type="text" id="secretId" />
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="secretKey" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.tencent.secretKey' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-label [nzSpan]="7" nzFor="secretKey" nzRequired="true">{{
|
||||
'alert.notice.sender.sms.tencent.secretKey' | i18n
|
||||
}}</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input [(ngModel)]="smsNoticeSender.tencent.secretKey" nz-input required name="secretKey" type="password" id="secretKey" />
|
||||
<input [(ngModel)]="smsNoticeSender.tencent.secretKey" nz-input required name="secretKey" type="text" id="secretKey" />
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
@@ -201,122 +191,7 @@
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="smsType === SmsType.ALIBABA">
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="accessKeyId" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.alibaba.accessKeyId' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input
|
||||
[(ngModel)]="smsNoticeSender.alibaba.accessKeyId"
|
||||
nz-input
|
||||
required
|
||||
name="accessKeyId"
|
||||
type="password"
|
||||
id="alibabaAccessKeyId"
|
||||
/>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="accessKeySecret" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.alibaba.accessKeySecret' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input
|
||||
[(ngModel)]="smsNoticeSender.alibaba.accessKeySecret"
|
||||
nz-input
|
||||
required
|
||||
name="accessKeySecret"
|
||||
type="password"
|
||||
id="alibabaAccessKeySecret"
|
||||
/>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="signName" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.alibaba.signName' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input [(ngModel)]="smsNoticeSender.alibaba.signName" nz-input required name="signName" type="text" id="alibabaSignName" />
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="templateCode" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.alibaba.templateCode' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input
|
||||
[(ngModel)]="smsNoticeSender.alibaba.templateCode"
|
||||
nz-input
|
||||
required
|
||||
name="templateCode"
|
||||
type="text"
|
||||
id="alibabaTemplateCode"
|
||||
/>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="smsType === SmsType.UNISMS">
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="accessKeyId" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.unisms.accessKeyId' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input
|
||||
[(ngModel)]="smsNoticeSender.unisms.accessKeyId"
|
||||
nz-input
|
||||
required
|
||||
name="accessKeyId"
|
||||
type="password"
|
||||
id="unismsAccessKeyId"
|
||||
/>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-label nzSpan="7" nzFor="authMode" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.unisms.authMode' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control nzSpan="12">
|
||||
<nz-select [(ngModel)]="smsNoticeSender.unisms.authMode" name="authMode" id="unismsAuthMode" required>
|
||||
<nz-option [nzValue]="uniSmsAuthModes.HMAC" nzLabel="HMAC"></nz-option>
|
||||
<nz-option [nzValue]="uniSmsAuthModes.SIMPLE" nzLabel="Simple"></nz-option>
|
||||
</nz-select>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
|
||||
<!-- accessKeySecret 根据 authMode 动态显示 -->
|
||||
<nz-form-item *ngIf="isAccessKeySecretRequired()">
|
||||
<nz-form-label [nzSpan]="7" nzFor="accessKeySecret" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.unisms.accessKeySecret' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input
|
||||
[(ngModel)]="smsNoticeSender.unisms.accessKeySecret"
|
||||
nz-input
|
||||
required
|
||||
name="accessKeySecret"
|
||||
type="password"
|
||||
id="unismsAccessKeySecret"
|
||||
/>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="signature" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.unisms.signature' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input [(ngModel)]="smsNoticeSender.unisms.signature" nz-input required name="signature" type="text" id="unismsSignature" />
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="templateId" nzRequired="true">
|
||||
{{ 'alert.notice.sender.sms.unisms.templateId' | i18n }}
|
||||
</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input [(ngModel)]="smsNoticeSender.unisms.templateId" nz-input required name="templateId" type="text" id="unismsTemplateId" />
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="smsType === 'alibaba'"> </ng-container>
|
||||
<nz-form-item>
|
||||
<nz-form-label nzSpan="7" nzFor="smsEnable" nzRequired="true">{{ 'common.enable' | i18n }}</nz-form-label>
|
||||
<nz-form-control nzSpan="12">
|
||||
|
||||
+21
-34
@@ -27,8 +27,6 @@ import { finalize } from 'rxjs/operators';
|
||||
import { AlibabaSmsConfig } from 'src/app/pojo/AlibabaSmsConfig';
|
||||
import { SmsNoticeSender } from 'src/app/pojo/SmsNoticeSender';
|
||||
import { TencentSmsConfig } from 'src/app/pojo/TencentSmsConfig';
|
||||
import { UniSmsConfig } from 'src/app/pojo/UniSmsConfig';
|
||||
import { SmsType, UniSmsAuthMode } from 'src/app/pojo/enums/sms-type.enum';
|
||||
|
||||
import { EmailNoticeSender } from '../../../../pojo/EmailNoticeSender';
|
||||
import { GeneralConfigService } from '../../../../service/general-config.service';
|
||||
@@ -51,13 +49,9 @@ export class MessageServerComponent implements OnInit {
|
||||
loading: boolean = false;
|
||||
isEmailServerModalVisible: boolean = false;
|
||||
isSmsServerModalVisible: boolean = false;
|
||||
smsType: SmsType = SmsType.TENCENT;
|
||||
smsType: string = 'tencent';
|
||||
emailSender = new EmailNoticeSender();
|
||||
smsNoticeSender = new SmsNoticeSender();
|
||||
uniSmsAuthModes = UniSmsAuthMode;
|
||||
SmsType = SmsType;
|
||||
private tempSmsType: SmsType = SmsType.TENCENT;
|
||||
private tempSmsNoticeSender = new SmsNoticeSender();
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadEmailSenderServer();
|
||||
@@ -137,14 +131,12 @@ export class MessageServerComponent implements OnInit {
|
||||
this.senderServerLoading = false;
|
||||
if (message.code === 0) {
|
||||
if (message.data) {
|
||||
const newSender = new SmsNoticeSender();
|
||||
this.smsNoticeSender = { ...newSender, ...message.data };
|
||||
this.smsNoticeSender.tencent = { ...new TencentSmsConfig(), ...message.data.tencent };
|
||||
this.smsNoticeSender.alibaba = { ...new AlibabaSmsConfig(), ...message.data.alibaba };
|
||||
this.smsNoticeSender.unisms = { ...new UniSmsConfig(), ...message.data.unisms };
|
||||
this.smsType = message.data.type || 'tencent';
|
||||
this.smsNoticeSender = message.data;
|
||||
this.smsType = message.data.type;
|
||||
} else {
|
||||
this.smsNoticeSender = new SmsNoticeSender();
|
||||
this.smsNoticeSender.type = 'tencent';
|
||||
this.smsNoticeSender.tencent = new TencentSmsConfig();
|
||||
}
|
||||
} else {
|
||||
console.warn(message.msg);
|
||||
@@ -160,34 +152,23 @@ export class MessageServerComponent implements OnInit {
|
||||
}
|
||||
|
||||
onConfigSmsServer() {
|
||||
this.tempSmsType = this.smsType;
|
||||
this.tempSmsNoticeSender = {
|
||||
...this.smsNoticeSender,
|
||||
tencent: { ...this.smsNoticeSender.tencent },
|
||||
alibaba: { ...this.smsNoticeSender.alibaba },
|
||||
unisms: { ...this.smsNoticeSender.unisms }
|
||||
};
|
||||
this.isSmsServerModalVisible = true;
|
||||
}
|
||||
|
||||
onCancelSmsServer() {
|
||||
this.smsType = this.tempSmsType;
|
||||
this.smsNoticeSender = {
|
||||
...this.tempSmsNoticeSender,
|
||||
tencent: { ...this.tempSmsNoticeSender.tencent },
|
||||
alibaba: { ...this.tempSmsNoticeSender.alibaba },
|
||||
unisms: { ...this.tempSmsNoticeSender.unisms }
|
||||
};
|
||||
this.isSmsServerModalVisible = false;
|
||||
}
|
||||
|
||||
onSmsTypeChange(value: SmsType) {
|
||||
this.smsType = value;
|
||||
this.smsNoticeSender.type = value;
|
||||
}
|
||||
|
||||
isAccessKeySecretRequired(): boolean {
|
||||
return this.smsNoticeSender.unisms.authMode === UniSmsAuthMode.HMAC;
|
||||
onSmsTypeChange(value: string) {
|
||||
if (value === 'tencent') {
|
||||
// tencent sms sender
|
||||
this.smsType = 'tencent';
|
||||
this.smsNoticeSender.type = 'tencent';
|
||||
} else if (value === 'alibaba') {
|
||||
// alibaba sms sender
|
||||
this.smsType = 'alibaba';
|
||||
this.smsNoticeSender.type = 'alibaba';
|
||||
}
|
||||
}
|
||||
|
||||
onSaveSmsServer() {
|
||||
@@ -200,6 +181,12 @@ export class MessageServerComponent implements OnInit {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.smsNoticeSender.type === 'tencent') {
|
||||
this.smsNoticeSender.alibaba = new AlibabaSmsConfig();
|
||||
}
|
||||
if (this.smsNoticeSender.type === 'alibaba') {
|
||||
this.smsNoticeSender.tencent = new TencentSmsConfig();
|
||||
}
|
||||
const modalOk$ = this.noticeSenderSvc
|
||||
.saveGeneralConfig(this.smsNoticeSender, 'sms')
|
||||
.pipe(
|
||||
|
||||
@@ -18,27 +18,27 @@
|
||||
-->
|
||||
|
||||
<nz-spin [nzSpinning]="loading">
|
||||
<div class="main" *ngIf="config">
|
||||
<div class="left">
|
||||
<form nz-form nzLayout="vertical" #objectStoreForm="ngForm" (submit)="onSaveObjectStore()">
|
||||
<div nz-row *ngIf="config">
|
||||
<div nz-col nzSpan="12">
|
||||
<form nz-form #objectStoreForm="ngForm" (submit)="onSaveObjectStore()">
|
||||
<nz-form-item>
|
||||
<nz-form-label nzFor="config.type">{{ 'settings.object-store.type' | i18n }}</nz-form-label>
|
||||
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
|
||||
<nz-select
|
||||
[(ngModel)]="config.type"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
style="text-align: center; font-weight: bolder; margin-top: 4px"
|
||||
[nzDropdownStyle]="{ 'font-weight': 'bolder', 'font-size': 'larger' }"
|
||||
(ngModelChange)="onChange()"
|
||||
>
|
||||
<nz-option [nzValue]="ObjectStoreType.FILE" [nzLabel]="'settings.object-store.type.file' | i18n"></nz-option>
|
||||
<nz-option [nzValue]="ObjectStoreType.DATABASE" [nzLabel]="'settings.object-store.type.database' | i18n"></nz-option>
|
||||
<nz-option [nzValue]="ObjectStoreType.OBS" [nzLabel]="'settings.object-store.type.obs' | i18n"></nz-option>
|
||||
</nz-select>
|
||||
</nz-form-control>
|
||||
<nz-form-label [nzSpan]="8" nzFor="config.type" nzRequired="true">{{ 'settings.object-store.type' | i18n }}</nz-form-label>
|
||||
<nz-select
|
||||
[(ngModel)]="config.type"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
style="text-align: center; font-weight: bolder"
|
||||
[nzDropdownStyle]="{ 'font-weight': 'bolder', 'font-size': 'larger' }"
|
||||
(ngModelChange)="onChange()"
|
||||
>
|
||||
<nz-option [nzValue]="ObjectStoreType.FILE" [nzLabel]="'settings.object-store.type.file' | i18n"></nz-option>
|
||||
<nz-option [nzValue]="ObjectStoreType.DATABASE" [nzLabel]="'settings.object-store.type.database' | i18n"></nz-option>
|
||||
<nz-option [nzValue]="ObjectStoreType.OBS" [nzLabel]="'settings.object-store.type.obs' | i18n"></nz-option>
|
||||
</nz-select>
|
||||
</nz-form-item>
|
||||
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS">
|
||||
<nz-form-label nzFor="obs.accessKey" nzRequired="true">{{ 'settings.object-store.obs.accessKey' | i18n }}</nz-form-label>
|
||||
<nz-form-label [nzSpan]="6" nzFor="obs.accessKey" nzRequired="true">{{
|
||||
'settings.object-store.obs.accessKey' | i18n
|
||||
}}</nz-form-label>
|
||||
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
|
||||
<input
|
||||
[(ngModel)]="config.config.accessKey"
|
||||
@@ -52,7 +52,9 @@
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS">
|
||||
<nz-form-label nzFor="obs.secretKey" nzRequired="true">{{ 'settings.object-store.obs.secretKey' | i18n }}</nz-form-label>
|
||||
<nz-form-label [nzSpan]="6" nzFor="obs.secretKey" nzRequired="true">{{
|
||||
'settings.object-store.obs.secretKey' | i18n
|
||||
}}</nz-form-label>
|
||||
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
|
||||
<input
|
||||
[(ngModel)]="config.config.secretKey"
|
||||
@@ -66,7 +68,9 @@
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS">
|
||||
<nz-form-label nzFor="obs.bucketName" nzRequired="true">{{ 'settings.object-store.obs.bucketName' | i18n }}</nz-form-label>
|
||||
<nz-form-label [nzSpan]="6" nzFor="obs.bucketName" nzRequired="true">{{
|
||||
'settings.object-store.obs.bucketName' | i18n
|
||||
}}</nz-form-label>
|
||||
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
|
||||
<input
|
||||
[(ngModel)]="config.config.bucketName"
|
||||
@@ -80,7 +84,9 @@
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS">
|
||||
<nz-form-label nzFor="obs.endpoint" nzRequired="true">{{ 'settings.object-store.obs.endpoint' | i18n }}</nz-form-label>
|
||||
<nz-form-label [nzSpan]="6" nzFor="obs.endpoint" nzRequired="true">{{
|
||||
'settings.object-store.obs.endpoint' | i18n
|
||||
}}</nz-form-label>
|
||||
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
|
||||
<input
|
||||
[(ngModel)]="config.config.endpoint"
|
||||
@@ -94,7 +100,9 @@
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS">
|
||||
<nz-form-label nzFor="obs.savePath" nzRequired="true">{{ 'settings.object-store.obs.savePath' | i18n }}</nz-form-label>
|
||||
<nz-form-label [nzSpan]="6" nzFor="obs.savePath" nzRequired="true">{{
|
||||
'settings.object-store.obs.savePath' | i18n
|
||||
}}</nz-form-label>
|
||||
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
|
||||
<input
|
||||
[(ngModel)]="config.config.savePath"
|
||||
|
||||
@@ -17,10 +17,8 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
|
||||
import { NgForm } from '@angular/forms';
|
||||
import { I18NService } from '@core';
|
||||
import { ALAIN_I18N_TOKEN } from '@delon/theme';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core';
|
||||
import { NzNotificationService } from 'ng-zorro-antd/notification';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
|
||||
@@ -36,19 +34,28 @@ const key = 'oss';
|
||||
})
|
||||
export class ObjectStoreComponent implements OnInit {
|
||||
constructor(
|
||||
private configService: GeneralConfigService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private notifySvc: NzNotificationService,
|
||||
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
|
||||
private configService: GeneralConfigService,
|
||||
@Inject(DOCUMENT) private doc: any
|
||||
) {}
|
||||
|
||||
loading = true;
|
||||
config!: ObjectStore<any>;
|
||||
@ViewChild('objectStoreForm', { static: false }) ruleForm: NgForm | undefined;
|
||||
isObjectStoreModalVisible: boolean = false;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadObjectStore();
|
||||
}
|
||||
|
||||
onConfigObjectStore() {
|
||||
this.isObjectStoreModalVisible = true;
|
||||
}
|
||||
|
||||
onCancelObjectStore() {
|
||||
this.isObjectStoreModalVisible = false;
|
||||
}
|
||||
|
||||
loadObjectStore() {
|
||||
this.loading = true;
|
||||
let configInit$ = this.configService.getGeneralConfig(key).subscribe(
|
||||
@@ -74,15 +81,6 @@ export class ObjectStoreComponent implements OnInit {
|
||||
}
|
||||
|
||||
onSaveObjectStore() {
|
||||
if (this.ruleForm?.invalid) {
|
||||
Object.values(this.ruleForm.controls).forEach(control => {
|
||||
if (control.invalid) {
|
||||
control.markAsDirty();
|
||||
control.updateValueAndValidity({ onlySelf: true });
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
const configOk$ = this.configService
|
||||
.saveGeneralConfig(this.config, key)
|
||||
@@ -95,13 +93,12 @@ export class ObjectStoreComponent implements OnInit {
|
||||
.subscribe(
|
||||
message => {
|
||||
if (message.code === 0) {
|
||||
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.apply-success'), '');
|
||||
} else {
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.apply-fail'), message.msg);
|
||||
// this.notifySvc.error(this.i18nSvc.fanyi('common.notify.apply-fail'), message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.apply-fail'), error.msg);
|
||||
// this.notifySvc.error(this.i18nSvc.fanyi('common.notify.apply-fail'), error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -118,5 +115,6 @@ export class ObjectStoreComponent implements OnInit {
|
||||
}
|
||||
};
|
||||
|
||||
protected readonly ObjectStore = ObjectStore;
|
||||
protected readonly ObjectStoreType = ObjectStoreType;
|
||||
}
|
||||
|
||||
@@ -210,24 +210,15 @@
|
||||
>
|
||||
<i nz-icon nzType="edit" nzTheme="outline"></i>
|
||||
</button>
|
||||
<button nz-button nz-dropdown [nzDropdownMenu]="more_menu">
|
||||
<span nz-icon nzType="ellipsis"></span>
|
||||
<button
|
||||
nz-button
|
||||
nzDanger
|
||||
(click)="onDeleteOneComponent(data.id)"
|
||||
nz-tooltip
|
||||
[nzTooltipTitle]="'status.component.delete' | i18n"
|
||||
>
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
</button>
|
||||
<nz-dropdown-menu #more_menu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
<li nz-menu-item>
|
||||
<button
|
||||
nz-button
|
||||
nzDanger
|
||||
(click)="onDeleteOneComponent(data.id)"
|
||||
nz-tooltip
|
||||
[nzTooltipTitle]="'status.component.delete' | i18n"
|
||||
>
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nz-dropdown-menu>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -306,24 +297,15 @@
|
||||
>
|
||||
<i nz-icon nzType="redo" nzTheme="outline"></i>
|
||||
</button>
|
||||
<button nz-button nz-dropdown [nzDropdownMenu]="more_menu">
|
||||
<span nz-icon nzType="ellipsis"></span>
|
||||
<button
|
||||
nz-button
|
||||
nzDanger
|
||||
(click)="onDeleteOneIncident(data.id)"
|
||||
nz-tooltip
|
||||
[nzTooltipTitle]="'status.incident.delete' | i18n"
|
||||
>
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
</button>
|
||||
<nz-dropdown-menu #more_menu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
<li nz-menu-item>
|
||||
<button
|
||||
nz-button
|
||||
nzDanger
|
||||
(click)="onDeleteOneIncident(data.id)"
|
||||
nz-tooltip
|
||||
[nzTooltipTitle]="'status.incident.delete' | i18n"
|
||||
>
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nz-dropdown-menu>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -42,12 +42,8 @@
|
||||
groupStyle="width: 250px;"
|
||||
[placeholder]="'label.search' | i18n"
|
||||
[(value)]="search"
|
||||
(keydown.enter)="loadTagsTable()"
|
||||
(cleared)="loadTagsTable()"
|
||||
(valueChange)="loadTagsTable()"
|
||||
/>
|
||||
<button nz-button nzType="primary" (click)="loadTagsTable()" class="mobile-hide">
|
||||
{{ 'common.search' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"alert.export.use-type": "Export rules in {{type}} file format",
|
||||
"alert.group-converge.delete": "Delete Converge Strategy",
|
||||
"alert.group-converge.edit": "Edit Converge Strategy",
|
||||
"alert.group-converge.enable": "Enable Converge",
|
||||
"alert.group-converge.group-interval": "Interval Time",
|
||||
"alert.group-converge.group-interval.tip": "Minimum interval for sending grouped alert notifications, avoid too frequent notifications, default 5 minutes",
|
||||
"alert.group-converge.group-labels": "Group Labels",
|
||||
@@ -144,19 +145,9 @@
|
||||
"alert.notice.sender.sms.tencent.secretKey": "Tencent Sms SecretKey",
|
||||
"alert.notice.sender.sms.tencent.signName": "Tencent Sms SignName",
|
||||
"alert.notice.sender.sms.tencent.templateId": "Tencent Sms TemplateId",
|
||||
"alert.notice.sender.sms.alibaba.accessKeyId": "Alibaba SMS AccessKeyId",
|
||||
"alert.notice.sender.sms.alibaba.accessKeySecret": "Alibaba SMS AccessKeySecret",
|
||||
"alert.notice.sender.sms.alibaba.signName": "Alibaba SMS Sign Name",
|
||||
"alert.notice.sender.sms.alibaba.templateCode": "Alibaba SMS Template Code",
|
||||
"alert.notice.sender.sms.unisms.accessKeyId": "UniSMS AccessKeyId",
|
||||
"alert.notice.sender.sms.unisms.accessKeySecret": "UniSMS AccessKeySecret",
|
||||
"alert.notice.sender.sms.unisms.signature": "UniSMS Signature",
|
||||
"alert.notice.sender.sms.unisms.templateId": "UniSMS TemplateId",
|
||||
"alert.notice.sender.sms.unisms.authMode": "UniSMS Authentication Mode",
|
||||
"alert.notice.sender.sms.type": "Sms Type",
|
||||
"alert.notice.sender.sms.type.alibaba": "Alibaba Sms",
|
||||
"alert.notice.sender.sms.type.tencent": "Tencent Sms",
|
||||
"alert.notice.sender.sms.type.unisms": "UniSMS",
|
||||
"alert.notice.template": "Notice Template",
|
||||
"alert.notice.template.content": "Template Content",
|
||||
"alert.notice.template.delete": "Delete Template",
|
||||
@@ -310,6 +301,7 @@
|
||||
"alert.severity.all": "All Severity",
|
||||
"alert.silence.delete": "Delete Silence Strategy",
|
||||
"alert.silence.edit": "Edit Silence Strategy",
|
||||
"alert.silence.enable": "Enable Silence",
|
||||
"alert.silence.labels": "Tag Match",
|
||||
"alert.silence.match-all": "Match All",
|
||||
"alert.silence.name": "Silence Strategy Name",
|
||||
@@ -432,7 +424,7 @@
|
||||
"common.copy.button": "Copy",
|
||||
"common.disable": "Disable",
|
||||
"common.edit": "Operate",
|
||||
"common.edit-time": "Edit Time",
|
||||
"common.edit-time": "Update Time",
|
||||
"common.enable": "Enable",
|
||||
"common.file.select": "Select File",
|
||||
"common.ignore": "Ignore",
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"alert.export.use-type": "{{type}}ファイル形式で閾値ルールをエクスポート",
|
||||
"alert.group-converge.delete": "収束戦略を削除",
|
||||
"alert.group-converge.edit": "収束戦略を編集",
|
||||
"alert.group-converge.enable": "収束を有効化",
|
||||
"alert.group-converge.group-interval": "間隔時間",
|
||||
"alert.group-converge.group-interval.tip": "グループ化されたアラート通知を送信する最小間隔時間。通知が頻繁になりすぎないように、デフォルトは5分です",
|
||||
"alert.group-converge.group-labels": "グループラベル",
|
||||
@@ -144,19 +145,9 @@
|
||||
"alert.notice.sender.sms.tencent.secretKey": "Tencent Sms SecretKey",
|
||||
"alert.notice.sender.sms.tencent.signName": "Tencent Sms SignName",
|
||||
"alert.notice.sender.sms.tencent.templateId": "Tencent Sms TemplateId",
|
||||
"alert.notice.sender.sms.alibaba.accessKeyId": "Alibaba SMS AccessKeyId",
|
||||
"alert.notice.sender.sms.alibaba.accessKeySecret": "Alibaba SMS AccessKeySecret",
|
||||
"alert.notice.sender.sms.alibaba.signName": "Alibaba SMS SignName",
|
||||
"alert.notice.sender.sms.alibaba.templateCode": "Alibaba SMS TemplateCode",
|
||||
"alert.notice.sender.sms.unisms.accessKeyId": "UniSMS AccessKeyId",
|
||||
"alert.notice.sender.sms.unisms.accessKeySecret": "UniSMS AccessKeySecret",
|
||||
"alert.notice.sender.sms.unisms.signature": "UniSMS Signature",
|
||||
"alert.notice.sender.sms.unisms.templateId": "UniSMS TemplateId",
|
||||
"alert.notice.sender.sms.unisms.authMode": "UniSMS認証モード",
|
||||
"alert.notice.sender.sms.type": "SMSタイプ",
|
||||
"alert.notice.sender.sms.type.alibaba": "Alibaba Sms",
|
||||
"alert.notice.sender.sms.type.tencent": "Tencent Sms",
|
||||
"alert.notice.sender.sms.type.unisms": "UniSMS",
|
||||
"alert.notice.template": "通知テンプレート",
|
||||
"alert.notice.template.content": "テンプレート内容",
|
||||
"alert.notice.template.delete": "テンプレートを削除",
|
||||
@@ -310,6 +301,7 @@
|
||||
"alert.severity.all": "すべての重大度",
|
||||
"alert.silence.delete": "サイレンス戦略を削除",
|
||||
"alert.silence.edit": "サイレンス戦略を編集",
|
||||
"alert.silence.enable": "サイレンスを有効化",
|
||||
"alert.silence.labels": "タグ一致",
|
||||
"alert.silence.match-all": "すべて一致",
|
||||
"alert.silence.name": "サイレンス戦略名",
|
||||
@@ -432,7 +424,7 @@
|
||||
"common.copy.button": "コピー",
|
||||
"common.disable": "無効化",
|
||||
"common.edit": "操作",
|
||||
"common.edit-time": "編集時間",
|
||||
"common.edit-time": "更新時間",
|
||||
"common.enable": "有効化",
|
||||
"common.file.select": "ファイルを選択",
|
||||
"common.ignore": "無視",
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"alert.export.use-type": "以 {{type}} 文件格式导出阈值规则",
|
||||
"alert.group-converge.delete": "删除分组策略",
|
||||
"alert.group-converge.edit": "编辑分组策略",
|
||||
"alert.group-converge.enable": "启用分组策略",
|
||||
"alert.group-converge.group-interval": "间隔时间",
|
||||
"alert.group-converge.group-interval.tip": "发送分组告警通知的最小时间间隔,避免告警通知过于频繁,默认5分钟",
|
||||
"alert.group-converge.group-labels": "分组标签",
|
||||
@@ -144,19 +145,9 @@
|
||||
"alert.notice.sender.sms.tencent.secretKey": "腾讯短信SecretKey",
|
||||
"alert.notice.sender.sms.tencent.signName": "腾讯短信SignName",
|
||||
"alert.notice.sender.sms.tencent.templateId": "腾讯短信TemplateId",
|
||||
"alert.notice.sender.sms.alibaba.accessKeyId": "阿里短信AccessKeyId",
|
||||
"alert.notice.sender.sms.alibaba.accessKeySecret": "阿里短信AccessKeySecret",
|
||||
"alert.notice.sender.sms.alibaba.signName": "阿里短信SignName",
|
||||
"alert.notice.sender.sms.alibaba.templateCode": "阿里短信TemplateCode",
|
||||
"alert.notice.sender.sms.unisms.accessKeyId": "合一短信AccessKeyId",
|
||||
"alert.notice.sender.sms.unisms.accessKeySecret": "合一短信AccessKeySecret",
|
||||
"alert.notice.sender.sms.unisms.signature": "合一短信Signature",
|
||||
"alert.notice.sender.sms.unisms.templateId": "合一短信TemplateId",
|
||||
"alert.notice.sender.sms.unisms.authMode": "合一短信鉴权方式",
|
||||
"alert.notice.sender.sms.type": "短信类型",
|
||||
"alert.notice.sender.sms.type.alibaba": "阿里短信",
|
||||
"alert.notice.sender.sms.type.tencent": "腾讯短信",
|
||||
"alert.notice.sender.sms.type.unisms": "合一短信(UniSMS)",
|
||||
"alert.notice.template": "通知模板",
|
||||
"alert.notice.template.content": "模板内容",
|
||||
"alert.notice.template.delete": "删除通知模板",
|
||||
@@ -310,6 +301,7 @@
|
||||
"alert.severity.all": "全部级别",
|
||||
"alert.silence.delete": "删除静默策略",
|
||||
"alert.silence.edit": "编辑静默策略",
|
||||
"alert.silence.enable": "启用静默策略",
|
||||
"alert.silence.labels": "匹配标签",
|
||||
"alert.silence.match-all": "应用所有",
|
||||
"alert.silence.name": "策略名称",
|
||||
@@ -432,8 +424,8 @@
|
||||
"common.copy.button": "复制",
|
||||
"common.disable": "关闭",
|
||||
"common.edit": "操作",
|
||||
"common.edit-time": "编辑时间",
|
||||
"common.enable": "启用状态",
|
||||
"common.edit-time": "更新时间",
|
||||
"common.enable": "是否启用",
|
||||
"common.file.select": "选择文件",
|
||||
"common.ignore": "忽略",
|
||||
"common.mute": "静音",
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"alert.export.use-type": "以 {{type}} 文件格式導出阈值規則",
|
||||
"alert.group-converge.delete": "刪除收斂策略",
|
||||
"alert.group-converge.edit": "編輯收斂策略",
|
||||
"alert.group-converge.enable": "啟用收斂策略",
|
||||
"alert.group-converge.group-interval": "間隔時間",
|
||||
"alert.group-converge.group-interval.tip": "發送分組告警通知的最小時間間隔,避免告警通知過於頻繁,默認5分鐘",
|
||||
"alert.group-converge.group-labels": "分組標籤",
|
||||
@@ -144,19 +145,9 @@
|
||||
"alert.notice.sender.sms.tencent.secretKey": "騰訊短訊SecretKey",
|
||||
"alert.notice.sender.sms.tencent.signName": "騰訊短訊SignName",
|
||||
"alert.notice.sender.sms.tencent.templateId": "騰訊短訊TemplateId",
|
||||
"alert.notice.sender.sms.alibaba.accessKeyId": "阿里短訊AccessKeyId",
|
||||
"alert.notice.sender.sms.alibaba.accessKeySecret": "阿里短訊AccessKeySecret",
|
||||
"alert.notice.sender.sms.alibaba.signName": "阿里短訊SignName",
|
||||
"alert.notice.sender.sms.alibaba.templateCode": "阿里短訊TemplateCode",
|
||||
"alert.notice.sender.sms.unisms.accessKeyId": "合一簡訊AccessKeyId",
|
||||
"alert.notice.sender.sms.unisms.accessKeySecret": "合一簡訊AccessKeySecret",
|
||||
"alert.notice.sender.sms.unisms.signature": "合一簡訊Signature",
|
||||
"alert.notice.sender.sms.unisms.templateId": "合一簡訊TemplateId",
|
||||
"alert.notice.sender.sms.unisms.authMode": "合一簡訊驗證方式",
|
||||
"alert.notice.sender.sms.type": "騰訊類型",
|
||||
"alert.notice.sender.sms.type.alibaba": "阿裏短訊",
|
||||
"alert.notice.sender.sms.type.tencent": "騰訊短訊",
|
||||
"alert.notice.sender.sms.type.unisms": "合一簡訊(UniSMS)",
|
||||
"alert.notice.template": "通知模板",
|
||||
"alert.notice.template.content": "模板内容",
|
||||
"alert.notice.template.delete": "刪除通知模板",
|
||||
@@ -310,6 +301,7 @@
|
||||
"alert.severity.all": "全部級別",
|
||||
"alert.silence.delete": "刪除靜默策略",
|
||||
"alert.silence.edit": "編輯靜默策略",
|
||||
"alert.silence.enable": "啟用靜默策略",
|
||||
"alert.silence.labels": "匹配標籤",
|
||||
"alert.silence.match-all": "應用所有",
|
||||
"alert.silence.name": "策略名稱",
|
||||
@@ -432,7 +424,7 @@
|
||||
"common.copy.button": "複製",
|
||||
"common.disable": "關閉",
|
||||
"common.edit": "操作",
|
||||
"common.edit-time": "編輯時間",
|
||||
"common.edit-time": "更新時間",
|
||||
"common.enable": "開啓",
|
||||
"common.file.select": "選擇文件",
|
||||
"common.ignore": "忽略",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
@primary-color: #3f51b5;
|
||||
@secondary-color: #8c8c8c;
|
||||
@highlight-blue: #d6e4ff;
|
||||
@border-color: #d9d9d9;
|
||||
@success-green: #52c41a;
|
||||
@error-red: #f5222d;
|
||||
@font-size-base: 14px;
|
||||
|
||||
Reference in New Issue
Block a user