mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-15 17:30:27 +08:00
feat: 通知渠道支持钉钉 (#14884)
* feat: 通知渠道支持钉钉 * fix: 还原错误的更改 * chore: 加回丢掉的换行符 * fix: 还原错误删除的内容
This commit is contained in:
@@ -290,6 +290,8 @@ public static class ConfigurationKeys
|
||||
public const string ExternalNotificationDiscordBotToken = "ExternalNotification.Discord.BotToken";
|
||||
public const string ExternalNotificationDiscordUserId = "ExternalNotification.Discord.UserId";
|
||||
public const string ExternalNotificationDiscordWebhookUrl = "ExternalNotification.Discord.WebhookUrl";
|
||||
public const string ExternalNotificationDingTalkAccessToken = "ExternalNotification.DingTalk.AccessToken";
|
||||
public const string ExternalNotificationDingTalkSecret = "ExternalNotification.DingTalk.Secret";
|
||||
public const string ExternalNotificationTelegramBotToken = "ExternalNotification.Telegram.BotToken";
|
||||
public const string ExternalNotificationTelegramChatId = "ExternalNotification.Telegram.ChatId";
|
||||
public const string ExternalNotificationTelegramTopicId = "ExternalNotification.TelegramTopicId";
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
<system:String x:Key="ExternalNotificationDiscordBotToken">Bot Token</system:String>
|
||||
<system:String x:Key="ExternalNotificationDiscordUserId">User ID</system:String>
|
||||
<system:String x:Key="ExternalNotificationDiscordWebhookUrl">Webhook URL</system:String>
|
||||
<system:String x:Key="ExternalNotificationDingTalkAccessToken">Access Token</system:String>
|
||||
<system:String x:Key="ExternalNotificationDingTalkSecret">Secret</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramBotToken">Bot Token</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramChatId">Chat ID</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramTopicId">Topic ID (Optional)</system:String>
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
<system:String x:Key="ExternalNotificationDiscordBotToken">ボットトークン</system:String>
|
||||
<system:String x:Key="ExternalNotificationDiscordUserId">ユーザーID</system:String>
|
||||
<system:String x:Key="ExternalNotificationDiscordWebhookUrl">ウェブフック URL</system:String>
|
||||
<system:String x:Key="ExternalNotificationDingTalkAccessToken">アクセストークン</system:String>
|
||||
<system:String x:Key="ExternalNotificationDingTalkSecret">シークレット</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramBotToken">ボットトークン</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramChatId">チャットID</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramTopicId">トピックID(任意)</system:String>
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
<system:String x:Key="ExternalNotificationDiscordBotToken">봇 토큰</system:String>
|
||||
<system:String x:Key="ExternalNotificationDiscordUserId">사용자 ID</system:String>
|
||||
<system:String x:Key="ExternalNotificationDiscordWebhookUrl">웹후크 URL</system:String>
|
||||
<system:String x:Key="ExternalNotificationDingTalkAccessToken">액세스 토큰</system:String>
|
||||
<system:String x:Key="ExternalNotificationDingTalkSecret">시크릿</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramBotToken">봇 토큰</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramChatId">채팅 ID</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramTopicId">토픽 ID (선택사항)</system:String>
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
<system:String x:Key="ExternalNotificationDiscordBotToken">机器人 Token</system:String>
|
||||
<system:String x:Key="ExternalNotificationDiscordUserId">用户 ID</system:String>
|
||||
<system:String x:Key="ExternalNotificationDiscordWebhookUrl">Webhook URL</system:String>
|
||||
<system:String x:Key="ExternalNotificationDingTalkAccessToken">Access Token</system:String>
|
||||
<system:String x:Key="ExternalNotificationDingTalkSecret">加签密钥</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramBotToken">机器人 Token</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramChatId">聊天 ID</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramTopicId">话题ID(可选)</system:String>
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
<system:String x:Key="ExternalNotificationDiscordBotToken">機器人 Token</system:String>
|
||||
<system:String x:Key="ExternalNotificationDiscordUserId">用戶 ID</system:String>
|
||||
<system:String x:Key="ExternalNotificationDiscordWebhookUrl">Webhook URL</system:String>
|
||||
<system:String x:Key="ExternalNotificationDingTalkAccessToken">Access Token</system:String>
|
||||
<system:String x:Key="ExternalNotificationDingTalkSecret">簽名密鑰</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramBotToken">機器人 Token</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramChatId">聊天 ID</system:String>
|
||||
<system:String x:Key="ExternalNotificationTelegramTopicId">話題 ID(可選)</system:String>
|
||||
|
||||
@@ -37,6 +37,7 @@ public static class ExternalNotificationService
|
||||
"ServerChan" => new ServerChanNotificationProvider(Instances.HttpService),
|
||||
"Telegram" => new TelegramNotificationProvider(Instances.HttpService),
|
||||
"Discord" => new DiscordNotificationProvider(Instances.HttpService),
|
||||
"DingTalk" => new DingTalkNotificationProvider(Instances.HttpService),
|
||||
"Discord Webhook" => new DiscordWebhookNotificationProvider(Instances.HttpService),
|
||||
"Custom Webhook" => new CustomWebhookNotificationProvider(Instances.HttpService),
|
||||
"SMTP" => new SmtpNotificationProvider(),
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
// <copyright file="DingTalkNotificationProvider.cs" company="MaaAssistantArknights">
|
||||
// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team)
|
||||
// Copyright (C) 2021-2025 MaaAssistantArknights Contributors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License v3.0 only as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY
|
||||
// </copyright>
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using MaaWpfGui.Services.Web;
|
||||
using MaaWpfGui.ViewModels.UI;
|
||||
using Serilog;
|
||||
|
||||
namespace MaaWpfGui.Services.Notification;
|
||||
|
||||
public class DingTalkNotificationProvider(IHttpService httpService) : IExternalNotificationProvider
|
||||
{
|
||||
private const string DingTalkWebhookEndpoint = "https://oapi.dingtalk.com/robot/send";
|
||||
private readonly ILogger _logger = Log.ForContext<DingTalkNotificationProvider>();
|
||||
|
||||
public async Task<bool> SendAsync(string title, string content)
|
||||
{
|
||||
var accessToken = SettingsViewModel.ExternalNotificationSettings.DingTalkAccessToken;
|
||||
var secret = SettingsViewModel.ExternalNotificationSettings.DingTalkSecret;
|
||||
|
||||
if (string.IsNullOrEmpty(accessToken))
|
||||
{
|
||||
_logger.Warning("Failed to send DingTalk notification: Access Token is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
var webhook = BuildWebhookUrl(accessToken, secret);
|
||||
var requestBody = new DingTalkPostContent
|
||||
{
|
||||
MessageType = "text",
|
||||
Text = new DingTalkTextContent
|
||||
{
|
||||
Content = $"{title}: {content}"
|
||||
}
|
||||
};
|
||||
|
||||
var response = await httpService.PostAsJsonAsync(new Uri(webhook), requestBody);
|
||||
if (response == null)
|
||||
{
|
||||
_logger.Warning("Failed to send DingTalk notification: response is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var responseData = JsonSerializer.Deserialize<DingTalkResponse>(response);
|
||||
if (responseData?.ErrorCode == 0)
|
||||
{
|
||||
_logger.Information("DingTalk notification sent successfully.");
|
||||
return true;
|
||||
}
|
||||
|
||||
_logger.Warning(
|
||||
"Failed to send DingTalk notification, error code: {ErrorCode}, error message: {ErrorMessage}",
|
||||
responseData?.ErrorCode,
|
||||
responseData?.ErrorMessage);
|
||||
return false;
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
_logger.Warning(ex, "Failed to parse DingTalk response.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildWebhookUrl(string accessToken, string? secret)
|
||||
{
|
||||
var builder = new StringBuilder($"{DingTalkWebhookEndpoint}?access_token={accessToken}");
|
||||
|
||||
if (string.IsNullOrEmpty(secret))
|
||||
{
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
var signBase = $"{timestamp}\n{secret}";
|
||||
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
|
||||
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(signBase));
|
||||
var sign = WebUtility.UrlEncode(Convert.ToBase64String(hash));
|
||||
builder.Append($"×tamp={timestamp}&sign={sign}");
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private class DingTalkPostContent
|
||||
{
|
||||
[JsonPropertyName("msgtype")]
|
||||
public string? MessageType { get; set; }
|
||||
|
||||
[JsonPropertyName("text")]
|
||||
public DingTalkTextContent? Text { get; set; }
|
||||
}
|
||||
|
||||
private class DingTalkTextContent
|
||||
{
|
||||
[JsonPropertyName("content")]
|
||||
public string? Content { get; set; }
|
||||
}
|
||||
|
||||
private class DingTalkResponse
|
||||
{
|
||||
[JsonPropertyName("errcode")]
|
||||
public int ErrorCode { get; set; }
|
||||
|
||||
[JsonPropertyName("errmsg")]
|
||||
public string? ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,7 @@ public class ExternalNotificationSettingsUserControlModel : PropertyChangedBase
|
||||
"ServerChan",
|
||||
"Telegram",
|
||||
"Discord",
|
||||
"DingTalk",
|
||||
"Discord Webhook",
|
||||
"SMTP",
|
||||
"Bark",
|
||||
@@ -164,6 +165,14 @@ public class ExternalNotificationSettingsUserControlModel : PropertyChangedBase
|
||||
set => SetAndNotify(ref _discordEnabled, value);
|
||||
}
|
||||
|
||||
private bool _dingTalkEnabled = false;
|
||||
|
||||
public bool DingTalkEnabled
|
||||
{
|
||||
get => _dingTalkEnabled;
|
||||
set => SetAndNotify(ref _dingTalkEnabled, value);
|
||||
}
|
||||
|
||||
private bool _discordWebhookEnabled = false;
|
||||
|
||||
public bool DiscordWebhookEnabled
|
||||
@@ -209,6 +218,7 @@ public class ExternalNotificationSettingsUserControlModel : PropertyChangedBase
|
||||
ServerChanEnabled = _enabledExternalNotificationProviders.Contains("ServerChan");
|
||||
TelegramEnabled = _enabledExternalNotificationProviders.Contains("Telegram");
|
||||
DiscordEnabled = _enabledExternalNotificationProviders.Contains("Discord");
|
||||
DingTalkEnabled = _enabledExternalNotificationProviders.Contains("DingTalk");
|
||||
DiscordWebhookEnabled = _enabledExternalNotificationProviders.Contains("Discord Webhook");
|
||||
SmtpEnabled = _enabledExternalNotificationProviders.Contains("SMTP");
|
||||
BarkEnabled = _enabledExternalNotificationProviders.Contains("Bark");
|
||||
@@ -400,6 +410,32 @@ public class ExternalNotificationSettingsUserControlModel : PropertyChangedBase
|
||||
}
|
||||
}
|
||||
|
||||
private string _dingTalkAccessToken = SimpleEncryptionHelper.Decrypt(ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationDingTalkAccessToken, string.Empty));
|
||||
|
||||
public string DingTalkAccessToken
|
||||
{
|
||||
get => _dingTalkAccessToken;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _dingTalkAccessToken, value);
|
||||
value = SimpleEncryptionHelper.Encrypt(value);
|
||||
ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationDingTalkAccessToken, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string _dingTalkSecret = SimpleEncryptionHelper.Decrypt(ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationDingTalkSecret, string.Empty));
|
||||
|
||||
public string DingTalkSecret
|
||||
{
|
||||
get => _dingTalkSecret;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _dingTalkSecret, value);
|
||||
value = SimpleEncryptionHelper.Encrypt(value);
|
||||
ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationDingTalkSecret, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string _telegramBotToken = SimpleEncryptionHelper.Decrypt(ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationTelegramBotToken, string.Empty));
|
||||
|
||||
public string TelegramBotToken
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!--<controls:TextBlock
|
||||
@@ -186,6 +187,31 @@
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="6"
|
||||
Orientation="Vertical"
|
||||
Visibility="{c:Binding DingTalkEnabled}">
|
||||
<hc:Divider Content="DingTalk" />
|
||||
<hc:PasswordBox
|
||||
x:Name="DingTalkAccessToken"
|
||||
Width="400"
|
||||
Height="30"
|
||||
Margin="10"
|
||||
hc:InfoElement.Title="{DynamicResource ExternalNotificationDingTalkAccessToken}"
|
||||
IsSafeEnabled="False"
|
||||
ShowEyeButton="True"
|
||||
UnsafePassword="{c:Binding DingTalkAccessToken}" />
|
||||
<hc:PasswordBox
|
||||
x:Name="DingTalkSecret"
|
||||
Width="400"
|
||||
Height="30"
|
||||
Margin="10"
|
||||
hc:InfoElement.Title="{DynamicResource ExternalNotificationDingTalkSecret}"
|
||||
IsSafeEnabled="False"
|
||||
ShowEyeButton="True"
|
||||
UnsafePassword="{c:Binding DingTalkSecret}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="7"
|
||||
HorizontalAlignment="Center"
|
||||
hc:InfoElement.TitleWidth="0"
|
||||
Visibility="{c:Binding SmtpEnabled}">
|
||||
@@ -326,7 +352,7 @@
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="7"
|
||||
Grid.Row="8"
|
||||
Orientation="Vertical"
|
||||
Visibility="{c:Binding BarkEnabled}">
|
||||
<hc:Divider Content="Bark" />
|
||||
@@ -349,7 +375,7 @@
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="8"
|
||||
Grid.Row="9"
|
||||
hc:InfoElement.TitleWidth="0"
|
||||
Orientation="Vertical"
|
||||
Visibility="{c:Binding QmsgEnabled}">
|
||||
@@ -437,7 +463,7 @@
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="9"
|
||||
Grid.Row="10"
|
||||
Orientation="Vertical"
|
||||
Visibility="{c:Binding CustomWebhookEnabled}">
|
||||
<hc:Divider Content="{DynamicResource ExternalNotificationCustomWebhook}" />
|
||||
|
||||
Reference in New Issue
Block a user