Skip to content

Commit

Permalink
fix!
Browse files Browse the repository at this point in the history
  • Loading branch information
Szer committed Oct 18, 2024
1 parent 3bcc323 commit 5c39b2e
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 55 deletions.
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# envs
BOT_TELEGRAM_TOKEN=SECRET_FROM_TELEGRAM
BOT_TELEGRAM_TOKEN=123:456
BOT_AUTH_TOKEN=JUST_YOUR_SECRET
BOT_HOOK_ROUTE=/bot
BOT_USER_ID=123456789
Expand All @@ -9,7 +9,7 @@ DEBUG=true
LOGS_CHANNEL_ID=-1000000000000
ALLOWED_USERS={"you":"123467890"}
CHATS_TO_MONITOR={"your_channel":"-100123467890"}
DATABASE_URL=Server=localhost;Database=vahter_bot_ban;Port=5432;User Id=vahter_bot_ban_service;Password=password;
DATABASE_URL='Server=localhost;Database=vahter_bot_ban;Port=5432;User Id=vahter_bot_ban_service;Password=password;'
OTEL_EXPORTER_ZIPKIN_ENDPOINT=http://zipkin:9411/api/v2/spans
OTEL_EXPORTER_CONSOLE=false
IGNORE_SIDE_EFFECTS=true
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0.302-jammy as build-env
FROM mcr.microsoft.com/dotnet/sdk:8.0.302-jammy AS build-env

### workaround for testcontainers resource reaper issue
ARG RESOURCE_REAPER_SESSION_ID="00000000-0000-0000-0000-000000000000"
Expand All @@ -13,7 +13,7 @@ COPY src/VahterBanBot .
COPY global.json .
RUN dotnet publish -c Release -o /publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0 as runtime
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /publish
COPY --from=build-env /publish .
ENTRYPOINT ["dotnet", "VahterBanBot.dll"]
91 changes: 48 additions & 43 deletions src/VahterBanBot.Tests/ContainerTestBase.fs
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ type VahterTestContainers() =
.WithPortBinding(80, true)
.WithEnvironment("BOT_USER_ID", "1337")
.WithEnvironment("BOT_USER_NAME", "test_bot")
.WithEnvironment("BOT_TELEGRAM_TOKEN", "TELEGRAM_SECRET")
.WithEnvironment("BOT_TELEGRAM_TOKEN", "123:456")
.WithEnvironment("BOT_AUTH_TOKEN", "OUR_SECRET")
.WithEnvironment("LOGS_CHANNEL_ID", "-123")
.WithEnvironment("CHATS_TO_MONITOR", """{"pro.hell": -666, "dotnetru": -42}""")
.WithEnvironment("ALLOWED_USERS", """{"vahter_1": 34, "vahter_2": 69}""")
.WithEnvironment("CHATS_TO_MONITOR", """{"pro.hell":-666,"dotnetru":-42}""")
.WithEnvironment("ALLOWED_USERS", """{"vahter_1":34,"vahter_2":69}""")
.WithEnvironment("SHOULD_DELETE_CHANNEL_MESSAGES", "true")
.WithEnvironment("IGNORE_SIDE_EFFECTS", "false")
.WithEnvironment("USE_FAKE_TG_API", "true")
Expand Down Expand Up @@ -116,46 +116,51 @@ type VahterTestContainers() =

interface IAsyncLifetime with
member this.InitializeAsync() = task {
// start building the image and spin up db at the same time
let imageTask = image.CreateAsync()
let dbTask = dbContainer.StartAsync()

// wait for both to finish
do! imageTask
do! dbTask
publicConnectionString <- $"Server=127.0.0.1;Database=vahter_bot_ban;Port={dbContainer.GetMappedPublicPort(5432)};User Id=vahter_bot_ban_service;Password=vahter_bot_ban_service;Include Error Detail=true;Minimum Pool Size=1;Maximum Pool Size=20;Max Auto Prepare=100;Auto Prepare Min Usages=1;Trust Server Certificate=true;"

// initialize DB with the schema, database and a DB user
let script = File.ReadAllText(CommonDirectoryPath.GetSolutionDirectory().DirectoryPath + "/init.sql")
let! initResult = dbContainer.ExecScriptAsync(script)
if initResult.Stderr <> "" then
failwith initResult.Stderr

// run migrations
do! flywayContainer.StartAsync()
let! out, err = flywayContainer.GetLogsAsync()
if err <> "" then
failwith err
if not (out.Contains "Successfully applied") then
failwith out

// seed some test data
let script = File.ReadAllText(CommonDirectoryPath.GetCallerFileDirectory().DirectoryPath + "/test_seed.sql")
let scriptFilePath = String.Join("/", String.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName())
do! dbContainer.CopyAsync(Encoding.Default.GetBytes script, scriptFilePath, Unix.FileMode644)
let! scriptResult = dbContainer.ExecAsync [|"psql"; "--username"; "vahter_bot_ban_service"; "--dbname"; "vahter_bot_ban"; "--file"; scriptFilePath |]

if scriptResult.Stderr <> "" then
failwith scriptResult.Stderr

// start the app container
do! appContainer.StartAsync()

// initialize the http client with correct hostname and port
httpClient <- new HttpClient()
uri <- Uri($"http://{appContainer.Hostname}:{appContainer.GetMappedPublicPort(80)}")
httpClient.BaseAddress <- uri
httpClient.DefaultRequestHeaders.Add("X-Telegram-Bot-Api-Secret-Token", "OUR_SECRET")
try
// start building the image and spin up db at the same time
let imageTask = image.CreateAsync()
let dbTask = dbContainer.StartAsync()

// wait for both to finish
do! imageTask
do! dbTask
publicConnectionString <- $"Server=127.0.0.1;Database=vahter_bot_ban;Port={dbContainer.GetMappedPublicPort(5432)};User Id=vahter_bot_ban_service;Password=vahter_bot_ban_service;Include Error Detail=true;Minimum Pool Size=1;Maximum Pool Size=20;Max Auto Prepare=100;Auto Prepare Min Usages=1;Trust Server Certificate=true;"

// initialize DB with the schema, database and a DB user
let script = File.ReadAllText(CommonDirectoryPath.GetSolutionDirectory().DirectoryPath + "/init.sql")
let! initResult = dbContainer.ExecScriptAsync(script)
if initResult.Stderr <> "" then
failwith initResult.Stderr

// run migrations
do! flywayContainer.StartAsync()
let! out, err = flywayContainer.GetLogsAsync()
if err <> "" then
failwith err
if not (out.Contains "Successfully applied") then
failwith out

// seed some test data
let script = File.ReadAllText(CommonDirectoryPath.GetCallerFileDirectory().DirectoryPath + "/test_seed.sql")
let scriptFilePath = String.Join("/", String.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName())
do! dbContainer.CopyAsync(Encoding.Default.GetBytes script, scriptFilePath, Unix.FileMode644)
let! scriptResult = dbContainer.ExecAsync [|"psql"; "--username"; "vahter_bot_ban_service"; "--dbname"; "vahter_bot_ban"; "--file"; scriptFilePath |]

if scriptResult.Stderr <> "" then
failwith scriptResult.Stderr

// start the app container
do! appContainer.StartAsync()

// initialize the http client with correct hostname and port
httpClient <- new HttpClient()
uri <- Uri($"http://{appContainer.Hostname}:{appContainer.GetMappedPublicPort(80)}")
httpClient.BaseAddress <- uri
httpClient.DefaultRequestHeaders.Add("X-Telegram-Bot-Api-Secret-Token", "OUR_SECRET")
finally
let struct (_, err) = appContainer.GetLogsAsync().Result
if err <> "" then
failwith err
}
member this.DisposeAsync() = task {
// stop all the containers, flyway might be dead already
Expand Down
2 changes: 1 addition & 1 deletion src/VahterBanBot.Tests/MessageTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type MessageTests(fixture: VahterTestContainers) =
message_id = msgUpdate.Message.MessageId
user_id = msgUpdate.Message.From.Id
text = msgUpdate.Message.Text
raw_message = $"""{{"chat": {{"id": -666, "type": "supergroup", "is_forum": false, "username": "pro.hell"}}, "date": {date}, "from": {{"id": {msg.From.Id}, "is_bot": false, "first_name": "{msg.From.FirstName}", "is_premium": false, "can_join_groups": false, "supports_inline_queries": false, "added_to_attachment_menu": false, "can_read_all_group_messages": false}}, "text": "{msg.Text}", "sticker": {{"type": "mask", "width": 512, "height": 512, "file_id": "sticker-id", "is_video": false, "is_animated": false, "file_unique_id": "sticker-uid", "needs_repainting": false}}, "entities": [{{"type": "code", "length": 6, "offset": 0}}], "message_id": {msg.MessageId}, "is_topic_message": false, "has_media_spoiler": false, "is_automatic_forward": false, "has_protected_content": false}}"""
raw_message = $"""{{"chat": {{"id": -666, "type": "supergroup", "is_forum": false, "username": "pro.hell"}}, "date": {date}, "from": {{"id": {msg.From.Id}, "is_bot": false, "first_name": "{msg.From.FirstName}", "is_premium": false, "can_join_groups": false, "has_main_web_app": false, "can_connect_to_business": false, "supports_inline_queries": false, "added_to_attachment_menu": false, "can_read_all_group_messages": false}}, "text": "{msg.Text}", "sticker": {{"type": "mask", "width": 512, "height": 512, "file_id": "sticker-id", "is_video": false, "is_animated": false, "file_unique_id": "sticker-uid", "needs_repainting": false}}, "entities": [{{"type": "code", "length": 6, "offset": 0}}], "message_id": {msg.MessageId}, "is_from_offline": false, "is_topic_message": false, "has_media_spoiler": false, "is_automatic_forward": false, "has_protected_content": false, "show_caption_above_media": false}}"""
created_at = dbMsg.Value.created_at },
dbMsg.Value
)
Expand Down
4 changes: 1 addition & 3 deletions src/VahterBanBot.Tests/VahterBanBot.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
</PropertyGroup>

<ItemGroup>
<Content Include="test_seed.sql">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="test_seed.sql" CopyToOutputDirectory="PreserveNewest" />
<Compile Include="TgMessageUtils.fs" />
<Compile Include="ContainerTestBase.fs" />
<Compile Include="BaseTests.fs" />
Expand Down
2 changes: 1 addition & 1 deletion src/VahterBanBot/FakeTgApi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ let fakeTgApi (botConf: BotConfiguration) =
member x.SendAsync(request, cancellationToken) =
let apiResult text =
let resp = new HttpResponseMessage(HttpStatusCode.OK)
resp.Content <- new StringContent($"""{{"Ok":true,"Result":{text}}}""", Encoding.UTF8, "application/json")
resp.Content <- new StringContent($"""{{"ok":true,"result":{text}}}""", Encoding.UTF8, "application/json")
resp

let url = request.RequestUri.ToString()
Expand Down
2 changes: 2 additions & 0 deletions src/VahterBanBot/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ let builder = WebApplication.CreateBuilder()
%builder.Services
.AddSingleton(botConf)
.AddGiraffe()
// we need to customize Giraffe STJ settings to conform to the Telegram.Bot API
.AddSingleton<Json.ISerializer>(Json.Serializer(jsonOptions))
.ConfigureTelegramBot<Microsoft.AspNetCore.Http.Json.JsonOptions>(fun x -> x.SerializerOptions)
.AddHostedService<CleanupService>()
.AddHostedService<StartupMessage>()
Expand Down
9 changes: 7 additions & 2 deletions src/VahterBanBot/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ open System
open System.Collections.Generic
open System.Text
open System.Text.Json
open System.Text.Json.Serialization
open Dapper
open Telegram.Bot.Types
open Utils
Expand Down Expand Up @@ -146,11 +147,15 @@ type DbCallback =

type CallbackMessageTypeHandler() =
inherit SqlMapper.TypeHandler<CallbackMessage>()
let callBackOptions =
let opts = JsonFSharpOptions.Default().ToJsonSerializerOptions()
Telegram.Bot.JsonBotAPI.Configure(opts)
opts

override this.SetValue(parameter, value) =
parameter.Value <- JsonSerializer.Serialize(value, options = jsonOptions)
parameter.Value <- JsonSerializer.Serialize(value, options = callBackOptions)
override this.Parse(value) =
JsonSerializer.Deserialize<CallbackMessage>(value.ToString(), options = jsonOptions)
JsonSerializer.Deserialize<CallbackMessage>(value.ToString(), options = callBackOptions)

[<CLIMutable>]
type UserStats =
Expand Down
2 changes: 1 addition & 1 deletion src/VahterBanBot/Utils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,6 @@ let jsonOptions =
// 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.DefaultIgnoreCondition <- System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull

baseOpts.SerializerOptions
1 change: 1 addition & 0 deletions src/VahterBanBot/VahterBanBot.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.2.0" />
<PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="Dapper.FSharp" Version="4.9.0" />
<PackageReference Include="FSharp.SystemTextJson" Version="1.3.13" />
<PackageReference Include="Giraffe" Version="7.0.2" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0" />
<PackageReference Include="Microsoft.ApplicationInsights.PerfCounterCollector" Version="2.22.0" />
Expand Down

0 comments on commit 5c39b2e

Please sign in to comment.