Skip to content

Commit

Permalink
Use UserId instead of Username for unban command (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
Keroosha authored Aug 15, 2023
1 parent 7436ca8 commit 96a0ddf
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 75 deletions.
63 changes: 29 additions & 34 deletions src/Grinder/Commands.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module Parser =
open FParsec

type Usernames = Usernames of string list
type UserIds = UserIds of int64 list

[<Measure>] type private parserError
type ParserError = string<parserError>
Expand Down Expand Up @@ -58,6 +59,7 @@ module Parser =

type Command =
| UserCommand of Usernames * CommandAction
| UserCommandWithIds of UserIds * CommandAction
| Ping

let str s = pstring s
Expand All @@ -83,6 +85,9 @@ module Parser =
let many1Usernames: Parser<string list, unit> =
many1 (pusername .>> spaces)

let many1UserId: Parser<int64 list, unit> =
many1 (pint64 .>> spaces)

let sumTimedFractions (fractions: TimeFraction list) =
let summator = TimeFractionSummator()
for fraction in fractions do
Expand Down Expand Up @@ -118,13 +123,14 @@ module Parser =

let pping: Parser<Command, unit> =
str "ping" >>% Ping

let pcommandAction: Parser<CommandAction, unit> =
pban <|> punban

let parseCommand botUsername =
pbotUsername botUsername >>.
(pping <|> pipe2 many1Usernames pcommandAction (fun usernames command -> UserCommand(Usernames(usernames), command)))
(
pping
<|> pipe2 many1Usernames pban (fun usernames command -> UserCommand(Usernames(usernames), command))
<|> pipe2 many1UserId punban (fun userIds command -> UserCommandWithIds(UserIds(userIds), command))
)

let runCommandParser botUsername str: ParserResult<Command, unit> =
run (parseCommand botUsername) str
Expand Down Expand Up @@ -279,7 +285,7 @@ module Processing =
From: UserUsername
MessageId: TelegramMessageId
ChatId: TelegramChatId
Usernames: UserUsername seq
UserIds: TelegramUserId seq
}

type PingContext = {
Expand Down Expand Up @@ -339,20 +345,20 @@ module Processing =
sprintf "Banned %s in chats %s %s" usernamesText chatsText durationText

type UnbanMessage =
{ Usernames: UserUsername seq
{ UserIds: TelegramUserId seq
Chats: ChatUsername seq }
interface IMessage with
member __.FormatAsString() =
let usernamesText =
__.Usernames
|> Seq.map ^ fun username -> %username
let userIds =
__.UserIds
|> Seq.map ^ fun x -> $"{x}"
|> String.join ", "

let chatsText =
__.Chats
|> Seq.map ^ fun chat -> %chat
|> String.join ", "
sprintf "Unbanned %s in chats %s" usernamesText chatsText
sprintf "Unbanned %s in chats %s" userIds chatsText

type CommandMessage =
| BanMessage of UserUsername * BanMessage * CommandError array
Expand Down Expand Up @@ -384,7 +390,7 @@ module Processing =
| _ -> DoNothingCommand

let parseTextMessage (context: TextMessageContext): Command =
match Parser.parse %context.BotUsername context.MessageText with
match parse %context.BotUsername context.MessageText with
| BotCommand(UserCommand((Usernames usernames), Ban(duration))) ->
let usernames =
usernames
Expand All @@ -398,22 +404,22 @@ module Processing =
Until = duration
}
BanCommand context
| BotCommand(UserCommand((Usernames usernames), Unban)) ->
let usernames =
usernames
|> Seq.map ^ fun username -> %username

| BotCommand(UserCommandWithIds(UserIds userIds, Unban)) ->
let userIds = userIds |> Seq.map ^ fun x -> %x
let context = {
From = %context.FromUsername
MessageId = %context.Message.MessageId
ChatId = %context.Message.Chat.Id
Usernames = usernames
UserIds = userIds
}
UnbanCommand context
| BotCommand(Ping) ->
PingCommand { ChatId = %context.Message.Chat.Id }
| InvalidCommand _ ->
DoNothingCommand
// Any miss-matched commands goes to "do nothing club"
| BotCommand command ->
DoNothingCommand

let executeCommand (botSettings: BotSettings) (botApi: IBotApi) (dataApi: IDataAccessApi) command: Async<CommandMessage option> = async {
let getErrors results =
Expand Down Expand Up @@ -519,7 +525,7 @@ module Processing =
do! botApi.DeleteMessage context.ChatId context.MessageId

let requests =
[for user in context.Usernames do
[for user in context.UserIds do
for chat in botSettings.ChatsToMonitor.Set do
yield botApi.UnbanUser chat user
|> Async.Map ^ Result.mapError
Expand All @@ -542,31 +548,20 @@ module Processing =

let message = {
Chats = botSettings.ChatsToMonitor.Set
Usernames = context.Usernames
UserIds = context.UserIds
}

return Some <| UnbanMessage(context.From, message, errors)
| UnbanOnReplyCommand context ->
let! username = async {
match context.Username with
| Some username ->
do! dataApi.UpsertUsers [DataAccess.User(UserId = %context.UserId, Username = %username)]
return username
| None ->
let! username = dataApi.GetUsernameByUserId context.UserId
return username
|> Option.map ^ fun name -> %(sprintf "@%s" %name)
|> Option.defaultValue %"unknown user"
}

let userId = context.UserId
do! botApi.DeleteMessage context.ChatId context.MessageId

let requests =
[for chat in botSettings.ChatsToMonitor.Set do
yield botApi.UnbanUser chat username
yield botApi.UnbanUser chat userId
|> Async.Map ^ Result.mapError
(sprintf "Error on unban user %A in chat %A. %s"
username
userId
chat
>> ApiError)]

Expand All @@ -579,7 +574,7 @@ module Processing =

let message = {
Chats = botSettings.ChatsToMonitor.Set
Usernames = Set.empty.Add username
UserIds = Set.empty.Add userId
}

return Some <| UnbanOnReplyMessage(context.From, message, errors)
Expand Down
44 changes: 18 additions & 26 deletions src/Grinder/Funogram.fs
Original file line number Diff line number Diff line change
Expand Up @@ -93,34 +93,26 @@ module ApiExt =
return Error <| sprintf "Failed to ban %i in chat %s. Description: %s" userId chat e.Description
}

let unbanUserByUsername context chat username onlyIfBanned = async {
match! Datastore.findUserIdByUsername username with
| UserIdFound userId ->
let! unbanResult =
unbanChatMemberByChatNameExt chat userId onlyIfBanned
|> callApiWithDefaultRetry context
match unbanResult with
| Ok _ ->
return Ok ()
| Error e ->
return Error <| sprintf "Failed to unban %s in chat %s. Description: %s" username chat e.Description
| UserIdNotFound ->
return Error <| sprintf "Couldn't resolve username %s" username
let unbanUserByUserId context chat userId onlyIfBanned = async {
let! unbanResult =
unbanChatMemberByChatNameExt chat userId onlyIfBanned
|> callApiWithDefaultRetry context
match unbanResult with
| Ok _ ->
return Ok ()
| Error e ->
return Error <| sprintf "Failed to unban %d in chat %s. Description: %s" userId chat e.Description
}

let unrestrictUserByUsername context chat username = async {
match! Datastore.findUserIdByUsername username with
| UserIdFound userId ->
let! restrictResult =
restrictChatMemberBase (Funogram.Types.String(chat)) userId None (Some true) (Some true) (Some true) (Some true)
|> callApiWithDefaultRetry context
match restrictResult with
| Ok _ ->
return Ok ()
| Error e ->
return Error <| sprintf "Failed to unrestrict %s in chat %s. Description: %s" username chat e.Description
| UserIdNotFound ->
return Error <| sprintf "Couldn't resolve username %s" username
let unrestrictUserByUserId context chat userId = async {
let! restrictResult =
restrictChatMemberBase (String(chat)) userId None (Some true) (Some true) (Some true) (Some true)
|> callApiWithDefaultRetry context
match restrictResult with
| Ok _ ->
return Ok ()
| Error e ->
return Error <| sprintf "Failed to unrestrict %d in chat %s. Description: %s" userId chat e.Description
}

let sendMessage (chatId: TelegramChatId) context text =
Expand Down
14 changes: 7 additions & 7 deletions src/Grinder/Program.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Grinder
namespace Grinder

open System.IO
open System.Net
Expand Down Expand Up @@ -79,10 +79,10 @@ module Program =
|> logInfo
ApiExt.banUserByUserId config %chatUsername %userId until

member __.UnbanUser chatUsername username: Async<Result<unit, string>> =
sprintf "Unbanning user %A in chat %A" username chatUsername
member __.UnbanUser chatUsername userId: Async<Result<unit, string>> =
sprintf "Unbanning user %d in chat %A" userId chatUsername
|> logInfo
ApiExt.unbanUserByUsername config %chatUsername %username true // Do nothing if user not banned
ApiExt.unbanUserByUserId config %chatUsername %userId true // Do nothing if user not banned

member __.SendTextMessage chatId text: Async<unit> =
sprintf "Sending {%s} into chat %A" text chatId
Expand All @@ -96,10 +96,10 @@ module Program =
|> logExn e
)

member __.UnrestrictUser chatUsername username: Async<Result<unit, string>> =
sprintf "Unrestricting user %A in chat %A"username chatUsername
member __.UnrestrictUser chatUsername userId: Async<Result<unit, string>> =
sprintf "Unrestricting user %d in chat %A"userId chatUsername
|> logInfo
ApiExt.unrestrictUserByUsername config %chatUsername %username
ApiExt.unrestrictUserByUserId config %chatUsername %userId

member __.SendTextToChannel text: Async<unit> =
sprintf "Sending {%s} into special channel %A" text settings.ChannelId
Expand Down
4 changes: 2 additions & 2 deletions src/Grinder/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ type IBotApi =
abstract member DeleteMessage: TelegramChatId -> TelegramMessageId -> Async<unit>
abstract member BanUserByUsername: ChatUsername -> UserUsername -> DateTime -> Async<Result<unit, string>>
abstract member BanUserByUserId: ChatUsername -> TelegramUserId -> DateTime -> Async<Result<unit, string>>
abstract member UnbanUser: ChatUsername -> UserUsername -> Async<Result<unit, string>>
abstract member UnrestrictUser: ChatUsername -> UserUsername -> Async<Result<unit, string>>
abstract member UnbanUser: ChatUsername -> TelegramUserId -> Async<Result<unit, string>>
abstract member UnrestrictUser: ChatUsername -> TelegramUserId -> Async<Result<unit, string>>
abstract member SendTextToChannel: string -> Async<unit>
abstract member SendTextMessage: TelegramChatId -> string -> Async<unit>
abstract member PrepareAndDownloadFile: string -> Async<Result<Stream, string>>
12 changes: 6 additions & 6 deletions tests/Grinder.Tests/CommandsTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -319,10 +319,10 @@ let ``BanMessage FormatAsString returns correct message when date is more than a

[<Fact>]
let ``UnbanMessage FormatAsString returns correct message``() =
let expected = """Unbanned @user1, @user2 in chats @chat1, @chat2"""
let expected = """Unbanned 123, 321 in chats @chat1, @chat2"""

let message = {
Usernames = [%"@user1"; %"@user2"]
UserIds = [%int64 123; %int64 321]
Chats = [%"@chat1"; %"@chat2"]
}

Expand Down Expand Up @@ -378,11 +378,11 @@ let ``formatMessage returns correct message for ban on reply message without err
[<Fact>]
let ``formatMessage returns correct message for unban``() = async {
let message = {
Usernames = [%"@user1"; %"@user2"]
UserIds = [%int64 123; %int64 321]
Chats = [%"@chat1"; %"@chat2"]
}

let expected = "Unban command from: @user\n\nUnbanned @user1, @user2 in chats @chat1, @chat2"
let expected = "Unban command from: @user\n\nUnbanned 123, 321 in chats @chat1, @chat2"

let commandMessage = UnbanMessage(%"user", message, [||])

Expand All @@ -392,11 +392,11 @@ let ``formatMessage returns correct message for unban``() = async {
[<Fact>]
let ``formatMessage returns correct message for unban on reply``() = async {
let message = {
Usernames = [%"@user1"; %"@user2"]
UserIds = [%int64 123; %int64 321]
Chats = [%"@chat1"; %"@chat2"]
}

let expected = "Unban on reply command from: @user\n\nUnbanned @user1, @user2 in chats @chat1, @chat2"
let expected = "Unban on reply command from: @user\n\nUnbanned 123, 321 in chats @chat1, @chat2"

let commandMessage = UnbanOnReplyMessage(%"user", message, [||])

Expand Down

0 comments on commit 96a0ddf

Please sign in to comment.