From 0603b24466e8f09a26beaabf8eba1da0fa09d95d Mon Sep 17 00:00:00 2001 From: Lightczx <1686188646@qq.com> Date: Thu, 26 Oct 2023 15:31:55 +0800 Subject: [PATCH] implement #431 --- .../Resource/Localization/SH.Designer.cs | 54 +++++++++++++++++++ .../Snap.Hutao/Resource/Localization/SH.resx | 18 +++++++ .../Service/Abstraction/DbStoreOptions.cs | 2 +- .../Service/DailyNote/DailyNoteOptions.cs | 7 +++ .../Service/DailyNote/DailyNoteService.cs | 6 +++ .../DailyNote/DailyNoteWebhookOperation.cs | 35 ++++++++++++ src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj | 7 +++ .../View/Dialog/DailyNoteWebhookDialog.xaml | 18 +++++++ .../Dialog/DailyNoteWebhookDialog.xaml.cs | 31 +++++++++++ .../View/Dialog/GachaLogUrlDialog.xaml | 2 +- .../View/Dialog/GachaLogUrlDialog.xaml.cs | 5 +- .../Snap.Hutao/View/Page/DailyNotePage.xaml | 9 +++- .../ViewModel/DailyNote/DailyNoteViewModel.cs | 13 +++++ .../HttpRequestMessageBuilderExtension.cs | 28 ++++++++++ 14 files changed, 230 insertions(+), 5 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteWebhookOperation.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/View/Dialog/DailyNoteWebhookDialog.xaml create mode 100644 src/Snap.Hutao/Snap.Hutao/View/Dialog/DailyNoteWebhookDialog.xaml.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs index 824cb508..5f9e467d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs @@ -2877,6 +2877,24 @@ namespace Snap.Hutao.Resource.Localization { } } + /// + /// 查找类似 请输入 Url 的本地化字符串。 + /// + internal static string ViewDialogDailyNoteWebhookUrlInputPlaceholder { + get { + return ResourceManager.GetString("ViewDialogDailyNoteWebhookUrlInputPlaceholder", resourceCulture); + } + } + + /// + /// 查找类似 实时便笺 Webhook Url 的本地化字符串。 + /// + internal static string ViewDialogDailyNoteWebhookUrlTitle { + get { + return ResourceManager.GetString("ViewDialogDailyNoteWebhookUrlTitle", resourceCulture); + } + } + /// /// 查找类似 导入祈愿记录 的本地化字符串。 /// @@ -3561,6 +3579,15 @@ namespace Snap.Hutao.Resource.Localization { } } + /// + /// 查找类似 配置实时便笺 Webhook Url 完成 的本地化字符串。 + /// + internal static string ViewModelDailyNoteConfigWebhookUrlComplete { + get { + return ResourceManager.GetString("ViewModelDailyNoteConfigWebhookUrlComplete", resourceCulture); + } + } + /// /// 查找类似 HoYoLab 账号不支持验证实时便笺 的本地化字符串。 /// @@ -4533,6 +4560,33 @@ namespace Snap.Hutao.Resource.Localization { } } + /// + /// 查找类似 在实时便笺刷新后推送到指定的 Webhook 的本地化字符串。 + /// + internal static string ViewPageDailyNoteConfigWebhookDescription { + get { + return ResourceManager.GetString("ViewPageDailyNoteConfigWebhookDescription", resourceCulture); + } + } + + /// + /// 查找类似 配置 Webhook 的本地化字符串。 + /// + internal static string ViewPageDailyNoteConfigWebhookHeader { + get { + return ResourceManager.GetString("ViewPageDailyNoteConfigWebhookHeader", resourceCulture); + } + } + + /// + /// 查找类似 数据互操作 的本地化字符串。 + /// + internal static string ViewPageDailyNoteDataInteropHeader { + get { + return ResourceManager.GetString("ViewPageDailyNoteDataInteropHeader", resourceCulture); + } + } + /// /// 查找类似 通知 的本地化字符串。 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 96616973..953f56b6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -1112,6 +1112,12 @@ 参量质变仪提醒 + + 请输入 Url + + + 实时便笺 Webhook Url + 导入祈愿记录 @@ -1340,6 +1346,9 @@ 不能添加名称无效的计划 + + 配置实时便笺 Webhook Url 完成 + HoYoLab 账号不支持验证实时便笺 @@ -1664,6 +1673,15 @@ 添加 + + 在实时便笺刷新后推送到指定的 Webhook + + + 配置 Webhook + + + 数据互操作 + 通知 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/DbStoreOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/DbStoreOptions.cs index 565201fc..85b95eb9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/DbStoreOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/DbStoreOptions.cs @@ -153,7 +153,7 @@ internal abstract partial class DbStoreOptions : ObservableObject, IOptions键 /// 值 /// 属性名称 - protected void SetOption(ref string? storage, string key, string value, [CallerMemberName] string? propertyName = null) + protected void SetOption(ref string? storage, string key, string? value, [CallerMemberName] string? propertyName = null) { if (!SetProperty(ref storage, value, propertyName)) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteOptions.cs index 819c8a50..215137e8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteOptions.cs @@ -27,6 +27,7 @@ internal sealed partial class DailyNoteOptions : DbStoreOptions private NameValue? selectedRefreshTime; private bool? isReminderNotification; private bool? isSilentWhenPlayingGame; + private string? webhookUrl; /// /// 刷新时间 @@ -122,4 +123,10 @@ internal sealed partial class DailyNoteOptions : DbStoreOptions get => GetOption(ref isSilentWhenPlayingGame, SettingEntry.DailyNoteSilentWhenPlayingGame); set => SetOption(ref isSilentWhenPlayingGame, SettingEntry.DailyNoteSilentWhenPlayingGame, value); } + + public string? WebhookUrl + { + get => GetOption(ref webhookUrl, SettingEntry.DailyNoteSilentWhenPlayingGame); + set => SetOption(ref webhookUrl, SettingEntry.DailyNoteSilentWhenPlayingGame, value); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs index 4d2cdf0b..19e93be7 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs @@ -3,12 +3,15 @@ using CommunityToolkit.Mvvm.Messaging; using Snap.Hutao.Core.DependencyInjection.Abstraction; +using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; using Snap.Hutao.Message; using Snap.Hutao.Model.Entity; using Snap.Hutao.Service.User; using Snap.Hutao.ViewModel.User; using Snap.Hutao.Web.Hoyolab; using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord; +using Snap.Hutao.Web.Request.Builder; +using Snap.Hutao.Web.Request.Builder.Abstraction; using System.Collections.ObjectModel; using WebDailyNote = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote.DailyNote; @@ -108,6 +111,8 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient(); + foreach (DailyNoteEntry entry in await dailyNoteDbService.GetDailyNoteEntryIncludeUserListAsync().ConfigureAwait(false)) { if (!forceRefresh && entry.DailyNote is not null) @@ -144,6 +149,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient logger; + private readonly DailyNoteOptions dailyNoteOptions; + private readonly HttpClient httpClient; + + public async ValueTask TryPostDailyNoteToWebhookAsync(WebDailyNote dailyNote, CancellationToken token = default) + { + string? targetUrl = dailyNoteOptions.WebhookUrl; + if (string.IsNullOrEmpty(targetUrl) || !Uri.TryCreate(targetUrl, UriKind.Absolute, out Uri? targetUri)) + { + return; + } + + HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() + .SetRequestUri(targetUri) + .PostJson(dailyNote); + + await builder.TryCatchSendAsync(httpClient, logger, token).ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index bdf870c4..7937c061 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -144,6 +144,7 @@ + @@ -312,6 +313,12 @@ + + + MSBuild:Compile + + + MSBuild:Compile diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/DailyNoteWebhookDialog.xaml b/src/Snap.Hutao/Snap.Hutao/View/Dialog/DailyNoteWebhookDialog.xaml new file mode 100644 index 00000000..62e6b268 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/DailyNoteWebhookDialog.xaml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/DailyNoteWebhookDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/DailyNoteWebhookDialog.xaml.cs new file mode 100644 index 00000000..3de9132a --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/DailyNoteWebhookDialog.xaml.cs @@ -0,0 +1,31 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.UI.Xaml.Controls; + +namespace Snap.Hutao.View.Dialog; + +[DependencyProperty("Text", typeof(string))] +internal sealed partial class DailyNoteWebhookDialog : ContentDialog +{ + private readonly ITaskContext taskContext; + + public DailyNoteWebhookDialog(IServiceProvider serviceProvider) + { + InitializeComponent(); + + taskContext = serviceProvider.GetRequiredService(); + } + + /// + /// 获取输入的Url + /// + /// 输入的结果 + public async ValueTask> GetInputUrlAsync() + { + await taskContext.SwitchToMainThreadAsync(); + ContentDialogResult result = await ShowAsync(); + + return new(result == ContentDialogResult.Primary, Text); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml b/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml index 71c3456c..3cc423c8 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml @@ -13,6 +13,6 @@ mc:Ignorable="d"> - + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml.cs index 480cd525..2e74c803 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml.cs @@ -9,6 +9,7 @@ namespace Snap.Hutao.View.Dialog; /// 祈愿记录Url对话框 /// [HighQuality] +[DependencyProperty("Text", typeof(string))] internal sealed partial class GachaLogUrlDialog : ContentDialog { private readonly ITaskContext taskContext; @@ -32,8 +33,8 @@ internal sealed partial class GachaLogUrlDialog : ContentDialog { await taskContext.SwitchToMainThreadAsync(); ContentDialogResult result = await ShowAsync(); - string url = InputText.Text.TrimEnd("#/log"); + string url = Text.TrimEnd("#/log"); return new(result == ContentDialogResult.Primary, url); } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml index 3ea16f55..b9da657b 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml @@ -159,7 +159,6 @@ - + + + diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs index 8bfeac98..69d267fd 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs @@ -123,4 +123,17 @@ internal sealed partial class DailyNoteViewModel : Abstraction.ViewModel } } } + + [Command("ConfigDailyNoteWebhookUrlCommand")] + private async Task ConfigDailyNoteWebhookUrlAsync() + { + DailyNoteWebhookDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false); + (bool isOk, string url) = await dialog.GetInputUrlAsync().ConfigureAwait(false); + + if (isOk) + { + options.WebhookUrl = url; + infoBarService.Information(SH.ViewModelDailyNoteConfigWebhookUrlComplete); + } + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Request/Builder/HttpRequestMessageBuilderExtension.cs b/src/Snap.Hutao/Snap.Hutao/Web/Request/Builder/HttpRequestMessageBuilderExtension.cs index 263d9825..51cb7539 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Request/Builder/HttpRequestMessageBuilderExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Request/Builder/HttpRequestMessageBuilderExtension.cs @@ -44,4 +44,32 @@ internal static class HttpRequestMessageBuilderExtension return default; } } + + internal static async ValueTask TryCatchSendAsync(this HttpRequestMessageBuilder builder, HttpClient httpClient, ILogger logger, CancellationToken token) + { + try + { + HttpResponseMessage message = await httpClient.SendAsync(builder.HttpRequestMessage, token).ConfigureAwait(false); + } + catch (HttpRequestException ex) + { + logger.LogWarning(ex, RequestErrorMessage); + } + catch (IOException ex) + { + logger.LogWarning(ex, RequestErrorMessage); + } + catch (JsonException ex) + { + logger.LogWarning(ex, RequestErrorMessage); + } + catch (HttpContentSerializationException ex) + { + logger.LogWarning(ex, RequestErrorMessage); + } + catch (SocketException ex) + { + logger.LogWarning(ex, RequestErrorMessage); + } + } } \ No newline at end of file