Skip to content

Commit

Permalink
even more message data (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
Szer authored Jul 8, 2024
1 parent 7da4833 commit 9a83a4d
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 80 deletions.
9 changes: 5 additions & 4 deletions src/VahterBanBot.Tests/ContainerTestBase.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ open Npgsql
open Telegram.Bot.Types
open Testcontainers.PostgreSql
open VahterBanBot.Tests.TgMessageUtils
open VahterBanBot.Types
open Xunit
open Dapper

Expand Down Expand Up @@ -158,12 +159,12 @@ type VahterTestContainers() =
Tg.chat(id = -42, username = "dotnetru")
]

member _.MessageExist(msg: Message) = task {
member _.TryGetDbMessage(msg: Message) = task {
use conn = new NpgsqlConnection(publicConnectionString)
//language=postgresql
let sql = "SELECT COUNT(*) FROM message WHERE chat_id = @chatId AND message_id = @messageId"
let! count = conn.QuerySingleAsync<int>(sql, {| chatId = msg.Chat.Id; messageId = msg.MessageId |})
return count = 1
let sql = "SELECT * FROM message WHERE chat_id = @chatId AND message_id = @messageId"
let! dbMessage = conn.QueryAsync<DbMessage>(sql, {| chatId = msg.Chat.Id; messageId = msg.MessageId |})
return dbMessage |> Seq.tryHead
}

member _.MessageBanned(msg: Message) = task {
Expand Down
38 changes: 38 additions & 0 deletions src/VahterBanBot.Tests/MessageTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module VahterBanBot.Tests.MessageTests

open System
open System.Net
open VahterBanBot.Types
open Telegram.Bot.Types
open Telegram.Bot.Types.Enums
open VahterBanBot.Tests.ContainerTestBase
open VahterBanBot.Tests.TgMessageUtils
open Xunit

type MessageTests(fixture: VahterTestContainers) =

[<Fact>]
let ``All data from the message being saved`` () = task {
// record just a message with some additional data
let msgUpdate = Tg.quickMsg(chat = fixture.ChatsToMonitor[0])
msgUpdate.Message.Entities <- [| MessageEntity(Type = MessageEntityType.Code, Offset = 0, Length = 6) |]
msgUpdate.Message.Sticker <- Sticker(Type = StickerType.Mask, Width = 512, Height = 512, FileId = "sticker-id", FileUniqueId = "sticker-uid")
let! _ = fixture.SendMessage msgUpdate

// assert that the message got recorded correctly
let! dbMsg = fixture.TryGetDbMessage msgUpdate.Message
Assert.True dbMsg.IsSome

let msg = msgUpdate.Message
let date = DateTimeOffset(msg.Date).ToUnixTimeSeconds()

Assert.Equal(
dbMsg.Value,
{ chat_id = msgUpdate.Message.Chat.Id
message_id = msgUpdate.Message.MessageId
user_id = msgUpdate.Message.From.Id
text = msgUpdate.Message.Text
raw_message = $"""{{"chat": {{"id": -666, "type": "unknown", "username": "pro.hell"}}, "date": {date}, "from": {{"id": {msg.From.Id}, "is_bot": false, "first_name": "{msg.From.FirstName}"}}, "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"}}, "entities": [{{"type": "code", "length": 6, "offset": 0}}], "message_id": {msg.MessageId}}}"""
created_at = dbMsg.Value.created_at }
)
}
16 changes: 8 additions & 8 deletions src/VahterBanBot.Tests/PingTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ type PingTests(fixture: VahterTestContainers) =
let msg = Tg.quickMsg(chat = fixture.ChatsToMonitor[0])

// assert that the message is not in the db
let! msgExist = fixture.MessageExist msg.Message
Assert.False msgExist
let! dbMsg = fixture.TryGetDbMessage msg.Message
Assert.False dbMsg.IsSome

// send the message to the bot
let! resp = fixture.SendMessage msg
Assert.Equal(HttpStatusCode.OK, resp.StatusCode)

// assert that the message is in the db
let! msgExist = fixture.MessageExist msg.Message
Assert.True msgExist
let! dbMsg = fixture.TryGetDbMessage msg.Message
Assert.True dbMsg.IsSome
}

[<Fact>]
Expand All @@ -31,16 +31,16 @@ type PingTests(fixture: VahterTestContainers) =
let msg = Tg.quickMsg(chat = Tg.chat())

// assert that the message is not in the db
let! msgExist = fixture.MessageExist msg.Message
Assert.False msgExist
let! dbMsg = fixture.TryGetDbMessage msg.Message
Assert.False dbMsg.IsSome

// send the message to the bot
let! resp = fixture.SendMessage msg
Assert.Equal(HttpStatusCode.OK, resp.StatusCode)

// assert that the message is still not in the db
let! msgExist = fixture.MessageExist msg.Message
Assert.False msgExist
let! dbMsg = fixture.TryGetDbMessage msg.Message
Assert.False dbMsg.IsSome
}

interface IAssemblyFixture<VahterTestContainers>
1 change: 1 addition & 0 deletions src/VahterBanBot.Tests/VahterBanBot.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<Compile Include="TgMessageUtils.fs" />
<Compile Include="ContainerTestBase.fs" />
<Compile Include="BaseTests.fs" />
<Compile Include="MessageTests.fs" />
<Compile Include="BanTests.fs" />
<Compile Include="PingTests.fs" />
<Compile Include="Program.fs"/>
Expand Down
14 changes: 7 additions & 7 deletions src/VahterBanBot/Bot.fs
Original file line number Diff line number Diff line change
Expand Up @@ -277,11 +277,11 @@ let banOnReply
use _ =
botActivity
.StartActivity("deleteMsg")
.SetTag("msgId", msg.Message_Id)
.SetTag("chatId", msg.Chat_Id)
do! botClient.DeleteMessageAsync(ChatId(msg.Chat_Id), msg.Message_Id)
.SetTag("msgId", msg.message_id)
.SetTag("chatId", msg.chat_id)
do! botClient.DeleteMessageAsync(ChatId(msg.chat_id), msg.message_id)
with e ->
logger.LogError ($"Failed to delete message {msg.Message_Id} from chat {msg.Chat_Id}", e)
logger.LogError ($"Failed to delete message {msg.message_id} from chat {msg.chat_id}", e)
})
|> Task.WhenAll
|> taskIgnore
Expand Down Expand Up @@ -363,9 +363,9 @@ let unban

let! user = DB.getUserById targetUserId
if user.IsSome then
%banOnReplyActivity.SetTag("targetUsername", user.Value.Username)
%banOnReplyActivity.SetTag("targetUsername", user.Value.username)

let targetUsername = user |> Option.bind (fun u -> u.Username)
let targetUsername = user |> Option.bind (_.username)

// try unban user in all monitored chats
let! unbanResults = unbanInAllChats botConfig botClient targetUserId
Expand Down Expand Up @@ -505,7 +505,7 @@ let onUpdate
if isNull message || isNull message.From then
logger.LogWarning "Received update without message"
else

// early return if we don't monitor this chat
if not (botConfig.ChatsToMonitor.ContainsValue message.Chat.Id) then
()
Expand Down
39 changes: 8 additions & 31 deletions src/VahterBanBot/DB.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,14 @@ let upsertUser (user: DbUser): Task<DbUser> =
let sql =
"""
INSERT INTO "user" (id, username, created_at, updated_at)
VALUES (@id, @username, @createdAt, @updatedAt)
VALUES (@id, @username, @created_at, @updated_at)
ON CONFLICT (id) DO UPDATE
SET username = COALESCE("user".username, EXCLUDED.username),
updated_at = GREATEST(EXCLUDED.updated_at, "user".updated_at)
RETURNING *;
"""

let! insertedUser =
conn.QueryAsync<DbUser>(
sql,
{| id = user.Id
username = user.Username
createdAt = user.Created_At
updatedAt = user.Updated_At |}
)
let! insertedUser = conn.QueryAsync<DbUser>(sql, user)

return insertedUser |> Seq.head
}
Expand All @@ -43,19 +36,12 @@ let insertMessage (message: DbMessage): Task<DbMessage> =
//language=postgresql
let sql =
"""
INSERT INTO message (chat_id, message_id, user_id, created_at)
VALUES (@chatId, @messageId, @userId, @createdAt)
INSERT INTO message (chat_id, message_id, user_id, text, raw_message, created_at)
VALUES (@chat_id, @message_id, @user_id, @text, @raw_message::JSONB, @created_at)
ON CONFLICT (chat_id, message_id) DO NOTHING RETURNING *;
"""

let! insertedMessage =
conn.QueryAsync<DbMessage>(
sql,
{| chatId = message.Chat_Id
messageId = message.Message_Id
userId = message.User_Id
createdAt = message.Created_At |}
)
let! insertedMessage = conn.QueryAsync<DbMessage>(sql, message)

return
insertedMessage
Expand All @@ -71,19 +57,10 @@ let banUser (banned: DbBanned): Task =
let sql =
"""
INSERT INTO banned (message_id, message_text, banned_user_id, banned_at, banned_in_chat_id, banned_in_chat_username, banned_by)
VALUES (@messageId, @messageText, @bannedUserId, @bannedAt, @bannedInChatId, @bannedInChatUsername, @bannedBy)
VALUES (@message_id, @message_text, @banned_user_id, @banned_at, @banned_in_chat_id, @banned_in_chat_username, @banned_by)
"""

let! _ = conn.ExecuteAsync(
sql,
{| messageId = banned.Message_Id
messageText = banned.Message_text
bannedUserId = banned.Banned_User_Id
bannedAt = banned.Banned_At
bannedInChatId = banned.Banned_In_Chat_Id
bannedInChatUsername = banned.Banned_In_Chat_username
bannedBy = banned.Banned_By |}
)
let! _ = conn.ExecuteAsync(sql, banned)
return banned
}

Expand All @@ -100,7 +77,7 @@ let getUserMessages (userId: int64): Task<DbMessage array> =

let deleteMsgs (msg: DbMessage[]): Task<int> =
task {
let msgIds = msg |> Array.map (fun m -> m.Message_Id)
let msgIds = msg |> Array.map (_.message_id)
use conn = new NpgsqlConnection(connString)

//language=postgresql
Expand Down
65 changes: 35 additions & 30 deletions src/VahterBanBot/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
open System
open System.Collections.Generic
open System.Text
open Newtonsoft.Json
open Utils

[<CLIMutable>]
Expand All @@ -23,52 +24,56 @@ type BotConfiguration =

[<CLIMutable>]
type DbUser =
{ Id: int64
Username: string option
Updated_At: DateTime
Created_At: DateTime }
{ id: int64
username: string option
updated_at: DateTime
created_at: DateTime }

static member newUser(id, ?username: string) =
{ Id = id
Username = username
Updated_At = DateTime.UtcNow
Created_At = DateTime.UtcNow }
{ id = id
username = username
updated_at = DateTime.UtcNow
created_at = DateTime.UtcNow }

static member newUser(user: Telegram.Bot.Types.User) =
DbUser.newUser (id = user.Id, ?username = Option.ofObj user.Username)

[<CLIMutable>]
type DbBanned =
{ Message_Id: int option
Message_text: string
Banned_User_Id: int64
Banned_At: DateTime
Banned_In_Chat_Id: int64 option
Banned_In_Chat_username: string option
Banned_By: int64 }
{ message_id: int option
message_text: string
banned_user_id: int64
banned_at: DateTime
banned_in_chat_id: int64 option
banned_in_chat_username: string option
banned_by: int64 }
module DbBanned =
let banMessage (vahter: int64) (message: Telegram.Bot.Types.Message) =
if isNull message.From || isNull message.Chat then
failwith "Message should have a user and a chat"
{ Message_Id = Some message.MessageId
Message_text = message.Text
Banned_User_Id = message.From.Id
Banned_At = DateTime.UtcNow
Banned_In_Chat_Id = Some message.Chat.Id
Banned_In_Chat_username = Some message.Chat.Username
Banned_By = vahter }
{ message_id = Some message.MessageId
message_text = message.Text
banned_user_id = message.From.Id
banned_at = DateTime.UtcNow
banned_in_chat_id = Some message.Chat.Id
banned_in_chat_username = Some message.Chat.Username
banned_by = vahter }

[<CLIMutable>]
type DbMessage =
{ Chat_Id: int64
Message_Id: int
User_Id: int64
Created_At: DateTime }
{ chat_id: int64
message_id: int
user_id: int64
text: string
raw_message: string
created_at: DateTime }
static member newMessage(message: Telegram.Bot.Types.Message) =
{ Chat_Id = message.Chat.Id
Message_Id = message.MessageId
User_Id = message.From.Id
Created_At = DateTime.UtcNow }
{ chat_id = message.Chat.Id
message_id = message.MessageId
user_id = message.From.Id
created_at = DateTime.UtcNow
text = message.Text
raw_message = JsonConvert.SerializeObject message }

[<CLIMutable>]
type VahterStat =
Expand Down
5 changes: 5 additions & 0 deletions src/migrations/V4__even-more-messages-info.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE message
ADD COLUMN text TEXT,
ADD COLUMN raw_message JSONB;

CREATE INDEX message_raw_message_idx ON message USING GIN (raw_message);

0 comments on commit 9a83a4d

Please sign in to comment.