diff --git a/src/VahterBanBot.Tests/ContainerTestBase.fs b/src/VahterBanBot.Tests/ContainerTestBase.fs index 1f9106a..88813fb 100644 --- a/src/VahterBanBot.Tests/ContainerTestBase.fs +++ b/src/VahterBanBot.Tests/ContainerTestBase.fs @@ -4,16 +4,17 @@ open System open System.IO open System.Net.Http open System.Text +open System.Text.Json open System.Threading.Tasks open DotNet.Testcontainers.Builders open DotNet.Testcontainers.Configurations open DotNet.Testcontainers.Containers -open Newtonsoft.Json open Npgsql open Telegram.Bot.Types open Testcontainers.PostgreSql open VahterBanBot.Tests.TgMessageUtils open VahterBanBot.Types +open VahterBanBot.Utils open Xunit open Dapper @@ -168,10 +169,10 @@ type VahterTestContainers() = member _.Uri = uri member this.SendMessage(update: Update) = task { - let json = JsonConvert.SerializeObject(update) + let json = JsonSerializer.Serialize(update, options = jsonOptions) return! this.SendMessage(json) } - + member _.SendMessage(json: string) = task { let content = new StringContent(json, Encoding.UTF8, "application/json") let! resp = httpClient.PostAsync("/bot", content) diff --git a/src/VahterBanBot.Tests/TgMessageUtils.fs b/src/VahterBanBot.Tests/TgMessageUtils.fs index ad97c34..80d43b3 100644 --- a/src/VahterBanBot.Tests/TgMessageUtils.fs +++ b/src/VahterBanBot.Tests/TgMessageUtils.fs @@ -3,6 +3,7 @@ module VahterBanBot.Tests.TgMessageUtils open System open System.Threading open Telegram.Bot.Types +open Telegram.Bot.Types.Enums type Tg() = static let mutable i = 1L // higher than the data in the test_seed.sql @@ -17,7 +18,8 @@ type Tg() = static member chat (?id: int64, ?username: string) = Chat( Id = (id |> Option.defaultValue (nextInt64())), - Username = (username |> Option.defaultValue null) + Username = (username |> Option.defaultValue null), + Type = ChatType.Supergroup ) static member callback(data: string, ?from: User) = diff --git a/src/VahterBanBot/FakeTgApi.fs b/src/VahterBanBot/FakeTgApi.fs index d11261f..f508f93 100644 --- a/src/VahterBanBot/FakeTgApi.fs +++ b/src/VahterBanBot/FakeTgApi.fs @@ -4,11 +4,12 @@ open System open System.Net open System.Net.Http open System.Text +open System.Text.Json open System.Threading.Tasks -open Newtonsoft.Json open Telegram.Bot.Types open Telegram.Bot.Types.Enums open VahterBanBot.Types +open VahterBanBot.Utils let fakeTgApi (botConf: BotConfiguration) = { new DelegatingHandler() with @@ -37,7 +38,7 @@ let fakeTgApi (botConf: BotConfiguration) = Type = ChatType.Private ) ) - |> JsonConvert.SerializeObject + |> fun x -> JsonSerializer.Serialize(x, options = jsonOptions) apiResult message elif url.EndsWith "/getChatAdministrators" then // respond with the request body as a string @@ -59,7 +60,7 @@ let fakeTgApi (botConf: BotConfiguration) = ) ) |] - |> JsonConvert.SerializeObject + |> fun x -> JsonSerializer.Serialize(x, options = jsonOptions) apiResult message else // return 500 for any other request diff --git a/src/VahterBanBot/Program.fs b/src/VahterBanBot/Program.fs index 87edd9c..0bdb6ef 100644 --- a/src/VahterBanBot/Program.fs +++ b/src/VahterBanBot/Program.fs @@ -2,6 +2,7 @@ open System open System.Collections.Generic +open System.Text.Json open System.Threading open System.Threading.Tasks open Dapper @@ -9,7 +10,6 @@ open Microsoft.AspNetCore.Builder open Microsoft.AspNetCore.Http open Microsoft.Extensions.Logging open Microsoft.FSharp.Core -open Newtonsoft.Json open Telegram.Bot open Telegram.Bot.Polling open Telegram.Bot.Types @@ -43,8 +43,8 @@ let botConf = BotUserId = getEnv "BOT_USER_ID" |> int64 BotUserName = getEnv "BOT_USER_NAME" LogsChannelId = getEnv "LOGS_CHANNEL_ID" |> int64 - ChatsToMonitor = getEnv "CHATS_TO_MONITOR" |> JsonConvert.DeserializeObject<_> - AllowedUsers = getEnv "ALLOWED_USERS" |> JsonConvert.DeserializeObject<_> + ChatsToMonitor = getEnv "CHATS_TO_MONITOR" |> JsonSerializer.Deserialize<_> + AllowedUsers = getEnv "ALLOWED_USERS" |> JsonSerializer.Deserialize<_> ShouldDeleteChannelMessages = getEnvOr "SHOULD_DELETE_CHANNEL_MESSAGES" "true" |> bool.Parse IgnoreSideEffects = getEnvOr "IGNORE_SIDE_EFFECTS" "false" |> bool.Parse UsePolling = getEnvOr "USE_POLLING" "false" |> bool.Parse @@ -67,7 +67,7 @@ let botConf = MlTrainingSetFraction = getEnvOr "ML_TRAINING_SET_FRACTION" "0.2" |> float MlSpamThreshold = getEnvOr "ML_SPAM_THRESHOLD" "0.5" |> single MlWarningThreshold = getEnvOr "ML_WARNING_THRESHOLD" "0.0" |> single - MlStopWordsInChats = getEnvOr "ML_STOP_WORDS_IN_CHATS" "{}" |> JsonConvert.DeserializeObject<_> } + MlStopWordsInChats = getEnvOr "ML_STOP_WORDS_IN_CHATS" "{}" |> JsonSerializer.Deserialize<_> } let validateApiKey (ctx : HttpContext) = match ctx.TryGetRequestHeader "X-Telegram-Bot-Api-Secret-Token" with @@ -81,6 +81,7 @@ let builder = WebApplication.CreateBuilder() %builder.Services .AddSingleton(botConf) .AddGiraffe() + .ConfigureTelegramBot(fun x -> x.SerializerOptions) .AddHostedService() .AddHostedService() .AddHostedService() @@ -153,7 +154,7 @@ let webApp = choose [ POST >=> route botConf.Route >=> requiresApiKey >=> bindJson (fun update next ctx -> task { let updateBodyJson = - try JsonConvert.SerializeObject update + try JsonSerializer.Serialize(update, options = jsonOptions) with e -> e.Message use topActivity = botActivity diff --git a/src/VahterBanBot/Types.fs b/src/VahterBanBot/Types.fs index afa79e4..001ba72 100644 --- a/src/VahterBanBot/Types.fs +++ b/src/VahterBanBot/Types.fs @@ -3,8 +3,8 @@ open System open System.Collections.Generic open System.Text +open System.Text.Json open Dapper -open Newtonsoft.Json open Telegram.Bot.Types open Utils @@ -93,7 +93,7 @@ type DbMessage = user_id = message.From.Id created_at = DateTime.UtcNow text = message.TextOrCaption - raw_message = JsonConvert.SerializeObject message } + raw_message = JsonSerializer.Serialize(message, options = jsonOptions) } [] type VahterStat = @@ -148,9 +148,9 @@ type CallbackMessageTypeHandler() = inherit SqlMapper.TypeHandler() override this.SetValue(parameter, value) = - parameter.Value <- JsonConvert.SerializeObject value + parameter.Value <- JsonSerializer.Serialize(value, options = jsonOptions) override this.Parse(value) = - JsonConvert.DeserializeObject(value.ToString()) + JsonSerializer.Deserialize(value.ToString(), options = jsonOptions) [] type UserStats = diff --git a/src/VahterBanBot/Utils.fs b/src/VahterBanBot/Utils.fs index 8deb0cd..c1ed60b 100644 --- a/src/VahterBanBot/Utils.fs +++ b/src/VahterBanBot/Utils.fs @@ -70,3 +70,16 @@ type Telegram.Bot.Types.Update with msg.Message else msg.EditedMessage + +// needed for STJ +let jsonOptions = + let baseOpts = Microsoft.AspNetCore.Http.Json.JsonOptions() + Telegram.Bot.JsonBotAPI.Configure(baseOpts.SerializerOptions) + + // HACK TIME + // there is a contradiction in Telegram.Bot library where User.IsBot is not nullable and required during deserialization, + // but it is omitted when default on deserialization via settings setup in JsonBotAPI.Configure + // so we'll override this setting explicitly + baseOpts.SerializerOptions.DefaultIgnoreCondition <- System.Text.Json.Serialization.JsonIgnoreCondition.Never + + baseOpts.SerializerOptions diff --git a/src/VahterBanBot/VahterBanBot.fsproj b/src/VahterBanBot/VahterBanBot.fsproj index 717efa3..8dfe3e1 100644 --- a/src/VahterBanBot/VahterBanBot.fsproj +++ b/src/VahterBanBot/VahterBanBot.fsproj @@ -23,10 +23,9 @@ - + -