1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-11-16 20:10:18 +00:00

Compare commits

..

39 Commits

Author SHA1 Message Date
af159b89b6 update changelog and readme 2023-09-25 23:26:05 +06:00
efe286c181 improvements and fixes in web apps api 2023-09-25 23:21:48 +06:00
821bb5b45c improve cloud storage 2023-09-25 20:23:37 +06:00
c92ed92f7c add opportunity to create Hex from rgb 2023-09-25 16:26:27 +06:00
88f6b349ea fixes in onEvent/onWriteAccessRequested/onContactRequested 2023-09-25 14:14:04 +06:00
6c4afac8f8 small refactor of chat member 2023-09-24 21:50:32 +06:00
6273990b00 fix in chat member deserializing 2023-09-24 21:33:26 +06:00
1a1fd926dd temporarily change request id main type to ushort 2023-09-24 21:12:48 +06:00
affa2a3a57 ChatAdministratorRightsImpl -> ChatCommonAdministratorRights 2023-09-24 20:11:58 +06:00
73a748d8b3 ChatAdministratorRights -> ChatAdministratorRightsImpl in reply keyboards 2023-09-24 20:08:46 +06:00
fa4d264df4 add preview callbacks support 2023-09-23 00:40:32 +06:00
1b1da33882 add CloudStorage support 2023-09-23 00:15:58 +06:00
ccfb774f33 update promoteChatMember 2023-09-22 23:33:56 +06:00
5215e8a315 add support of stories rights 2023-09-22 22:53:14 +06:00
97a3901cb9 improvements of WriteAccessAllowed 2023-09-22 21:55:22 +06:00
034e87a8ef add support of several new things in bot api 2023-09-22 21:45:28 +06:00
156fbd72d4 start 9.2.0 2023-09-22 21:10:21 +06:00
8ec3e01737 Update build.gradle 2023-09-02 09:36:11 +06:00
1655bedabe Merge pull request #788 from InsanusMokrassar/9.1.2
9.1.2
2023-09-01 03:52:37 +06:00
ac6b580a7e fixes in message content serialization 2023-09-01 02:42:39 +06:00
c6692c2509 start 9.1.2 2023-09-01 02:20:53 +06:00
12846a68b9 Merge pull request #785 from InsanusMokrassar/9.1.1
9.1.1
2023-08-31 20:39:30 +06:00
21f5808b12 small refactoring 2023-08-31 19:35:01 +06:00
64244a60fe potential fix of incorrect parsing in 'RawMessageEntity' 2023-08-31 19:20:42 +06:00
4cd7fdb436 start 9.1.1 2023-08-31 19:03:36 +06:00
6daf98d47d Merge pull request #783 from InsanusMokrassar/9.1.0
9.1.0
2023-08-20 02:35:25 +06:00
c260597799 fixes in poll answer 2023-08-20 02:30:36 +06:00
d59e204002 rename PollAnswer inheritors 2023-08-20 00:27:33 +06:00
117d891ff2 update changelog and PollAnswer 2023-08-19 23:55:59 +06:00
1e451af508 update telegram bot api support info 2023-08-19 18:40:12 +06:00
051f5e22e7 fix of createResend in story content 2023-08-19 18:15:54 +06:00
6873c23309 complete story support 2023-08-19 16:41:08 +06:00
a65971be00 start add stories 2023-08-19 00:31:36 +06:00
4b5baaff8c add suport of unpinAllGeneralForumTopicMessages 2023-08-18 23:34:44 +06:00
0840d2e083 add emoji_status_expiration_date support in Chat 2023-08-18 23:31:30 +06:00
085a225eb4 add support of voter_chat in PollAnswer 2023-08-18 23:27:15 +06:00
b575871a8e update dependencies 2023-08-18 23:13:56 +06:00
c96e162845 start 9.1.0 2023-08-18 23:05:43 +06:00
c471d59b3c Merge pull request #774 from InsanusMokrassar/9.0.0
9.0.0
2023-07-01 14:37:43 +06:00
57 changed files with 1472 additions and 142 deletions

View File

@@ -1,5 +1,31 @@
# TelegramBotAPI changelog
## 9.2.0
**Add support of [Telegram Bots API 6.9](https://core.telegram.org/bots/api-changelog#september-22-2023)**
* Rename `ChatAdministratorRightsImpl` -> `ChatCommonAdministratorRights`
* All the request chat keyboards has changed their parameters `ChatAdministratorRights` to `ChatCommonAdministratorRights`
## 9.1.2
* `Core`:
* Fix of `MessageContent` serialization
## 9.1.1
* `Core`:
* Potential fix of incorrect parsing in `RawMessageEntity`
## 9.1.0
**This update contains adding of [Telegram Bot API 6.8](https://core.telegram.org/bots/api-changelog#august-18-2023) support**
* `Version`:
* `Coroutines`: `1.7.2` -> `1.7.3`
* `Ktor`: `2.3.2` -> `2.3.3`
* `MicroUtils`: `0.19.7` -> `0.19.9`
## 9.0.0
**THIS UPDATE CONTAINS BREAKING CHANGES: USERNAMES OF BOTS NOW BECAME NULLABLE**

View File

@@ -1,4 +1,4 @@
# TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-6.7-blue)](https://core.telegram.org/bots/api-changelog#april-21-2023)
# TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-6.9-blue)](https://core.telegram.org/bots/api-changelog#september-22-2023)
| Docs | [![KDocs](https://img.shields.io/static/v1?label=Dokka&message=KDocs&color=blue&logo=kotlin)](https://tgbotapi.inmo.dev/index.html) [![Mini tutorial](https://img.shields.io/static/v1?label=Mk&message=Docs&color=blue&logo=mkdocs)](https://docs.inmo.dev/tgbotapi/index.html) |
|:----------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|

View File

@@ -54,7 +54,7 @@ Object callback = {
skipDeprecated.set(true)
sourceLink {
localDirectory.set(file("./"))
localDirectory.set(file("../"))
remoteUrl.set(new URL("https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/"))
remoteLineSuffix.set("#L")
}

View File

@@ -6,4 +6,4 @@ kotlin.incremental=true
kotlin.incremental.js=true
library_group=dev.inmo
library_version=9.0.0
library_version=9.2.0

View File

@@ -2,18 +2,18 @@
kotlin = "1.8.22"
kotlin-serialization = "1.5.1"
kotlin-coroutines = "1.7.2"
kotlin-coroutines = "1.7.3"
javax-activation = "1.1.1"
korlibs = "4.0.3"
uuid = "0.7.1"
ktor = "2.3.2"
ktor = "2.3.3"
ksp = "1.8.22-1.0.11"
kotlin-poet = "1.14.2"
microutils = "0.19.7"
microutils = "0.19.9"
github-release-plugin = "2.4.1"
dokka = "1.8.20"

View File

@@ -2,17 +2,17 @@ package dev.inmo.tgbotapi.extensions.api.bot
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.bot.SetMyDefaultAdministratorRights
import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRightsImpl
import dev.inmo.tgbotapi.types.chat.member.ChatCommonAdministratorRights
suspend fun TelegramBot.setMyDefaultAdministratorRights(
rights: ChatAdministratorRightsImpl,
rights: ChatCommonAdministratorRights,
forChannels: Boolean? = null
) = execute(SetMyDefaultAdministratorRights(rights, forChannels))
suspend fun TelegramBot.setMyDefaultAdministratorRightsForChannels(
rights: ChatAdministratorRightsImpl
rights: ChatCommonAdministratorRights
) = setMyDefaultAdministratorRights(rights, forChannels = true)
suspend fun TelegramBot.setMyDefaultAdministratorRightsForGroupsAndSupergroups(
rights: ChatAdministratorRightsImpl
rights: ChatCommonAdministratorRights
) = setMyDefaultAdministratorRights(rights, forChannels = false)

View File

@@ -0,0 +1,21 @@
package dev.inmo.tgbotapi.extensions.api.chat.forum
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.forum.UnpinAllForumTopicMessages
import dev.inmo.tgbotapi.requests.chat.forum.UnpinAllGeneralForumTopicMessages
import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.ForumTopic
import dev.inmo.tgbotapi.types.MessageThreadId
import dev.inmo.tgbotapi.types.chat.Chat
suspend fun TelegramBot.unpinAllGeneralForumTopicMessages(
chatId: ChatIdentifier
) = execute(
UnpinAllGeneralForumTopicMessages(
chatId
)
)
suspend fun TelegramBot.unpinAllGeneralForumTopicMessages(
chat: Chat
) = unpinAllGeneralForumTopicMessages(chat.id)

View File

@@ -0,0 +1,157 @@
package dev.inmo.tgbotapi.extensions.api.chat.members
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.members.PromoteChannelAdministrator
import dev.inmo.tgbotapi.requests.chat.members.PromoteChatMember
import dev.inmo.tgbotapi.types.IdChatIdentifier
import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.chat.PublicChat
import dev.inmo.tgbotapi.types.chat.User
suspend fun TelegramBot.promoteChannelAdministrator(
chatId: ChatIdentifier,
userId: UserId,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canPostMessages: Boolean? = null,
canEditMessages: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canPostStories: Boolean? = null,
canEditStories: Boolean? = null,
canDeleteStories: Boolean? = null
) = execute(
PromoteChannelAdministrator(
chatId = chatId,
userId = userId,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = canPostMessages,
canEditMessages = canEditMessages,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canPostStories = canPostStories,
canEditStories = canEditStories,
canDeleteStories = canDeleteStories
)
)
suspend fun TelegramBot.promoteChannelAdministrator(
chat: PublicChat,
userId: UserId,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canPostMessages: Boolean? = null,
canEditMessages: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canPostStories: Boolean? = null,
canEditStories: Boolean? = null,
canDeleteStories: Boolean? = null
) = promoteChannelAdministrator(
chat.id,
userId,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = canPostMessages,
canEditMessages = canEditMessages,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canPostStories = canPostStories,
canEditStories = canEditStories,
canDeleteStories = canDeleteStories
)
suspend fun TelegramBot.promoteChannelAdministrator(
chatId: IdChatIdentifier,
user: User,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canPostMessages: Boolean? = null,
canEditMessages: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canPostStories: Boolean? = null,
canEditStories: Boolean? = null,
canDeleteStories: Boolean? = null
) = promoteChannelAdministrator(
chatId,
user.id,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = canPostMessages,
canEditMessages = canEditMessages,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canPostStories = canPostStories,
canEditStories = canEditStories,
canDeleteStories = canDeleteStories
)
suspend fun TelegramBot.promoteChannelAdministrator(
chat: PublicChat,
user: User,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canPostMessages: Boolean? = null,
canEditMessages: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canPostStories: Boolean? = null,
canEditStories: Boolean? = null,
canDeleteStories: Boolean? = null
) = promoteChannelAdministrator(
chat.id,
user.id,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = canPostMessages,
canEditMessages = canEditMessages,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canPostStories = canPostStories,
canEditStories = canEditStories,
canDeleteStories = canDeleteStories
)

View File

@@ -0,0 +1,116 @@
package dev.inmo.tgbotapi.extensions.api.chat.members
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.members.PromoteChatMember
import dev.inmo.tgbotapi.types.IdChatIdentifier
import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.chat.PublicChat
import dev.inmo.tgbotapi.types.chat.User
suspend fun TelegramBot.promoteChatAdministrator(
chatId: ChatIdentifier,
userId: UserId,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
) = execute(
PromoteChatMember(
chatId,
userId,
untilDate,
isAnonymous,
canChangeInfo,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPromoteMembers,
canManageVideoChats,
canManageChat
)
)
suspend fun TelegramBot.promoteChatAdministrator(
chat: PublicChat,
userId: UserId,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
) = promoteChatAdministrator(
chat.id,
userId,
untilDate,
isAnonymous,
canChangeInfo,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPromoteMembers,
canManageVideoChats,
canManageChat
)
suspend fun TelegramBot.promoteChatAdministrator(
chatId: IdChatIdentifier,
user: User,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
) = promoteChatAdministrator(
chatId,
user.id,
untilDate,
isAnonymous,
canChangeInfo,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPromoteMembers,
canManageVideoChats,
canManageChat
)
suspend fun TelegramBot.promoteChatAdministrator(
chat: PublicChat,
user: User,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
) = promoteChatAdministrator(
chat.id,
user.id,
untilDate,
isAnonymous,
canChangeInfo,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPromoteMembers,
canManageVideoChats,
canManageChat
)

View File

@@ -1,14 +1,13 @@
package dev.inmo.tgbotapi.extensions.api.chat.members
import dev.inmo.micro_utils.common.Warning
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.members.PromoteChatMember
import dev.inmo.tgbotapi.types.IdChatIdentifier
import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.PublicChat
import dev.inmo.tgbotapi.types.chat.User
@Warning("This method is too common. Use it with caution")
suspend fun TelegramBot.promoteChatMember(
chatId: ChatIdentifier,
userId: UserId,
@@ -24,27 +23,34 @@ suspend fun TelegramBot.promoteChatMember(
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canManageTopics: Boolean? = null
canManageTopics: Boolean? = null,
canPostStories: Boolean? = null,
canEditStories: Boolean? = null,
canDeleteStories: Boolean? = null
) = execute(
PromoteChatMember(
chatId,
userId,
untilDate,
isAnonymous,
canChangeInfo,
canPostMessages,
canEditMessages,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPinMessages,
canPromoteMembers,
canManageVideoChats,
canManageChat,
canManageTopics
chatId = chatId,
userId = userId,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = canPostMessages,
canEditMessages = canEditMessages,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = canPinMessages,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = canManageTopics,
canPostStories = canPostStories,
canEditStories = canEditStories,
canDeleteStories = canDeleteStories
)
)
@Warning("This method is too common. Use it with caution")
suspend fun TelegramBot.promoteChatMember(
chat: PublicChat,
userId: UserId,
@@ -60,25 +66,32 @@ suspend fun TelegramBot.promoteChatMember(
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canManageTopics: Boolean? = null
canManageTopics: Boolean? = null,
canPostStories: Boolean? = null,
canEditStories: Boolean? = null,
canDeleteStories: Boolean? = null
) = promoteChatMember(
chat.id,
userId,
untilDate,
isAnonymous,
canChangeInfo,
canPostMessages,
canEditMessages,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPinMessages,
canPromoteMembers,
canManageVideoChats,
canManageChat,
canManageTopics
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = canPostMessages,
canEditMessages = canEditMessages,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = canPinMessages,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = canManageTopics,
canPostStories = canPostStories,
canEditStories = canEditStories,
canDeleteStories = canDeleteStories
)
@Warning("This method is too common. Use it with caution")
suspend fun TelegramBot.promoteChatMember(
chatId: IdChatIdentifier,
user: User,
@@ -94,25 +107,32 @@ suspend fun TelegramBot.promoteChatMember(
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canManageTopics: Boolean? = null
canManageTopics: Boolean? = null,
canPostStories: Boolean? = null,
canEditStories: Boolean? = null,
canDeleteStories: Boolean? = null
) = promoteChatMember(
chatId,
user.id,
untilDate,
isAnonymous,
canChangeInfo,
canPostMessages,
canEditMessages,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPinMessages,
canPromoteMembers,
canManageVideoChats,
canManageChat,
canManageTopics
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = canPostMessages,
canEditMessages = canEditMessages,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = canPinMessages,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = canManageTopics,
canPostStories = canPostStories,
canEditStories = canEditStories,
canDeleteStories = canDeleteStories
)
@Warning("This method is too common. Use it with caution")
suspend fun TelegramBot.promoteChatMember(
chat: PublicChat,
user: User,
@@ -128,21 +148,27 @@ suspend fun TelegramBot.promoteChatMember(
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canManageTopics: Boolean? = null
canManageTopics: Boolean? = null,
canPostStories: Boolean? = null,
canEditStories: Boolean? = null,
canDeleteStories: Boolean? = null
) = promoteChatMember(
chat.id,
user.id,
untilDate,
isAnonymous,
canChangeInfo,
canPostMessages,
canEditMessages,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPinMessages,
canPromoteMembers,
canManageVideoChats,
canManageChat,
canManageTopics
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = canPostMessages,
canEditMessages = canEditMessages,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = canPinMessages,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = canManageTopics,
canPostStories = canPostStories,
canEditStories = canEditStories,
canDeleteStories = canDeleteStories
)

View File

@@ -0,0 +1,133 @@
package dev.inmo.tgbotapi.extensions.api.chat.members
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.chat.members.PromoteChatMember
import dev.inmo.tgbotapi.requests.chat.members.PromoteSupergroupAdministrator
import dev.inmo.tgbotapi.types.IdChatIdentifier
import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.chat.PublicChat
import dev.inmo.tgbotapi.types.chat.User
suspend fun TelegramBot.promoteSupergroupAdministrator(
chatId: ChatIdentifier,
userId: UserId,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPinMessages: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canManageTopics: Boolean? = null,
) = execute(
PromoteSupergroupAdministrator(
chatId = chatId,
userId = userId,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = canPinMessages,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = canManageTopics
)
)
suspend fun TelegramBot.promoteSupergroupAdministrator(
chat: PublicChat,
userId: UserId,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPinMessages: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canManageTopics: Boolean? = null,
) = promoteSupergroupAdministrator(
chat.id,
userId,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = canPinMessages,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = canManageTopics
)
suspend fun TelegramBot.promoteSupergroupAdministrator(
chatId: IdChatIdentifier,
user: User,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPinMessages: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canManageTopics: Boolean? = null,
) = promoteSupergroupAdministrator(
chatId,
user.id,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = canPinMessages,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = canManageTopics
)
suspend fun TelegramBot.promoteSupergroupAdministrator(
chat: PublicChat,
user: User,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPinMessages: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canManageTopics: Boolean? = null,
) = promoteSupergroupAdministrator(
chat.id,
user.id,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = canPinMessages,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = canManageTopics
)

View File

@@ -62,6 +62,10 @@ suspend fun BehaviourContext.waitText(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent(initRequest, errorFactory).mapContent<TextContent>()
suspend fun BehaviourContext.waitStory(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent(initRequest, errorFactory).mapContent<StoryContent>()
suspend fun BehaviourContext.waitVenue(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }

View File

@@ -74,6 +74,10 @@ suspend fun BehaviourContext.waitTextMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage(initRequest, errorFactory).mapWithContent<TextContent>()
suspend fun BehaviourContext.waitStoryMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage(initRequest, errorFactory).mapWithContent<StoryContent>()
suspend fun BehaviourContext.waitVenueMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }

View File

@@ -174,6 +174,25 @@ suspend fun BehaviourContext.waitWriteAccessAllowed(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitEvents<WriteAccessAllowed>(initRequest, errorFactory)
suspend fun BehaviourContext.waitWriteAccessAllowedFromRequest(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitEvents<WriteAccessAllowed.FromRequest>(initRequest, errorFactory)
suspend fun BehaviourContext.waitWriteAccessAllowedFromAttachmentMenu(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitEvents<WriteAccessAllowed.FromAttachmentMenu>(initRequest, errorFactory)
suspend fun BehaviourContext.waitWriteAccessAllowedFromWebAppLink(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitEvents<WriteAccessAllowed.FromWebAppLink>(initRequest, errorFactory)
suspend fun BehaviourContext.waitWriteAccessAllowedOther(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitEvents<WriteAccessAllowed.Other>(initRequest, errorFactory)
suspend fun BehaviourContext.waitChatSharedRequest(
initRequest: Request<*>? = null,

View File

@@ -171,6 +171,22 @@ suspend fun BehaviourContext.waitWriteAccessAllowedEventsMessages(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitEventsMessages<WriteAccessAllowed>(initRequest, errorFactory)
suspend fun BehaviourContext.waitWriteAccessAllowedFromRequestEventsMessages(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitEventsMessages<WriteAccessAllowed.FromRequest>(initRequest, errorFactory)
suspend fun BehaviourContext.waitWriteAccessAllowedFromAttachmentMenuEventsMessages(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitEventsMessages<WriteAccessAllowed.FromAttachmentMenu>(initRequest, errorFactory)
suspend fun BehaviourContext.waitWriteAccessAllowedFromWebAppLinkEventsMessages(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitEventsMessages<WriteAccessAllowed.FromWebAppLink>(initRequest, errorFactory)
suspend fun BehaviourContext.waitWriteAccessAllowedOtherEventsMessages(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }
) = waitEventsMessages<WriteAccessAllowed.Other>(initRequest, errorFactory)
suspend fun BehaviourContext.waitChatSharedRequestEventsMessages(
initRequest: Request<*>? = null,

View File

@@ -248,6 +248,30 @@ suspend fun <BC : BehaviourContext> BC.onText(
scenarioReceiver
)
/**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param [markerFactory] Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onStory(
initialFilter: CommonMessageFilter<StoryContent>? = CommonMessageFilterExcludeMediaGroups,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, StoryMessage, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in StoryMessage, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, StoryMessage>
) = onContentMessageWithType(
initialFilter,
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,

View File

@@ -655,10 +655,90 @@ suspend fun <BC : BehaviourContext> BC.onGeneralForumTopicUnhidden(
* data
*/
suspend fun <BC : BehaviourContext> BC.onWriteAccessAllowed(
initialFilter: SimpleFilter<SupergroupEventMessage<WriteAccessAllowed>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, SupergroupEventMessage<WriteAccessAllowed>, Update>? = MessageFilterByChat,
initialFilter: SimpleFilter<ChatEventMessage<WriteAccessAllowed>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<WriteAccessAllowed>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<WriteAccessAllowed>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, SupergroupEventMessage<WriteAccessAllowed>>
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<WriteAccessAllowed>>
) = onEventWithCustomChatEventMessage(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
/**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param markerFactory Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onWriteAccessAllowedFromRequest(
initialFilter: SimpleFilter<ChatEventMessage<WriteAccessAllowed.FromRequest>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<WriteAccessAllowed.FromRequest>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<WriteAccessAllowed.FromRequest>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<WriteAccessAllowed.FromRequest>>
) = onEventWithCustomChatEventMessage(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
/**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param markerFactory Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onWriteAccessAllowedFromAttachmentMenu(
initialFilter: SimpleFilter<ChatEventMessage<WriteAccessAllowed.FromAttachmentMenu>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<WriteAccessAllowed.FromAttachmentMenu>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<WriteAccessAllowed.FromAttachmentMenu>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<WriteAccessAllowed.FromAttachmentMenu>>
) = onEventWithCustomChatEventMessage(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
/**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param markerFactory Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onWriteAccessAllowedOther(
initialFilter: SimpleFilter<ChatEventMessage<WriteAccessAllowed.Other>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<WriteAccessAllowed.Other>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<WriteAccessAllowed.Other>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<WriteAccessAllowed.Other>>
) = onEventWithCustomChatEventMessage(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
/**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
* @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,
* this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage].
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own.
* Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times]
* to combinate several filters
* @param markerFactory Will be used to identify different "stream". [scenarioReceiver] will be called synchronously
* in one "stream". Output of [markerFactory] will be used as a key for "stream"
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
* data
*/
suspend fun <BC : BehaviourContext> BC.onWriteAccessAllowedFromWebAppLink(
initialFilter: SimpleFilter<ChatEventMessage<WriteAccessAllowed.FromWebAppLink>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<WriteAccessAllowed.FromWebAppLink>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<WriteAccessAllowed.FromWebAppLink>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<WriteAccessAllowed.FromWebAppLink>>
) = onEventWithCustomChatEventMessage(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)

View File

@@ -2,14 +2,14 @@ package dev.inmo.tgbotapi.requests.bot
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRightsImpl
import dev.inmo.tgbotapi.types.chat.member.ChatCommonAdministratorRights
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
class SetMyDefaultAdministratorRights(
@SerialName(rightsField)
val rights: ChatAdministratorRightsImpl,
val rights: ChatCommonAdministratorRights,
@SerialName(forChannelsField)
val forChannels: Boolean? = null
) : SimpleRequest<Boolean> {

View File

@@ -0,0 +1,14 @@
package dev.inmo.tgbotapi.requests.chat.forum
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.*
@Serializable
data class UnpinAllGeneralForumTopicMessages (
@SerialName(chatIdField)
override val chatId: ChatIdentifier,
): ModifyForumRequest {
override fun method(): String = "unpinAllGeneralForumTopicMessages"
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -1,5 +1,6 @@
package dev.inmo.tgbotapi.requests.chat.members
import dev.inmo.micro_utils.common.Warning
import dev.inmo.tgbotapi.abstracts.types.UntilDate
import dev.inmo.tgbotapi.requests.chat.abstracts.ChatMemberRequest
import dev.inmo.tgbotapi.types.*
@@ -7,6 +8,7 @@ import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
@Warning("This method is too common. Use it with caution")
data class PromoteChatMember(
@SerialName(chatIdField)
override val chatId: ChatIdentifier,
@@ -37,7 +39,13 @@ data class PromoteChatMember(
@SerialName(canManageChatField)
private val canManageChat: Boolean? = null,
@SerialName(canManageTopicsField)
private val canManageTopics: Boolean? = null
private val canManageTopics: Boolean? = null,
@SerialName(canPostStoriesField)
private val canPostStories: Boolean? = null,
@SerialName(canEditStoriesField)
private val canEditStories: Boolean? = null,
@SerialName(canDeleteStoriesField)
private val canDeleteStories: Boolean? = null
) : ChatMemberRequest<Boolean>, UntilDate {
override fun method(): String = "promoteChatMember"
override val resultDeserializer: DeserializationStrategy<Boolean>
@@ -45,3 +53,109 @@ data class PromoteChatMember(
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}
fun PromoteChatMember(
chatId: ChatIdentifier,
userId: UserId,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
) = PromoteChatMember(
chatId = chatId,
userId = userId,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = null,
canEditMessages = null,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = null,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = null,
canPostStories = null,
canEditStories = null,
canDeleteStories = null
)
fun PromoteChannelAdministrator(
chatId: ChatIdentifier,
userId: UserId,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canPostMessages: Boolean? = null,
canEditMessages: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canPostStories: Boolean? = null,
canEditStories: Boolean? = null,
canDeleteStories: Boolean? = null
) = PromoteChatMember(
chatId = chatId,
userId = userId,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = canPostMessages,
canEditMessages = canEditMessages,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = null,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = null,
canPostStories = canPostStories,
canEditStories = canEditStories,
canDeleteStories = canDeleteStories
)
fun PromoteSupergroupAdministrator(
chatId: ChatIdentifier,
userId: UserId,
untilDate: TelegramDate? = null,
isAnonymous: Boolean? = null,
canChangeInfo: Boolean? = null,
canDeleteMessages: Boolean? = null,
canInviteUsers: Boolean? = null,
canRestrictMembers: Boolean? = null,
canPinMessages: Boolean? = null,
canPromoteMembers: Boolean? = null,
canManageVideoChats: Boolean? = null,
canManageChat: Boolean? = null,
canManageTopics: Boolean? = null,
) = PromoteChatMember(
chatId = chatId,
userId = userId,
untilDate = untilDate,
isAnonymous = isAnonymous,
canChangeInfo = canChangeInfo,
canPostMessages = null,
canEditMessages = null,
canDeleteMessages = canDeleteMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = canPinMessages,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
canManageTopics = canManageTopics,
canPostStories = null,
canEditStories = null,
canDeleteStories = null
)

View File

@@ -177,6 +177,11 @@ val stickerKeywordLengthLimit = 0 .. 64
const val botActionActualityTime: Seconds = 5
val cloudStorageKeyLimit = 1 .. 128
val cloudStorageValueLimit = 0 .. 4096
val cloudStorageKeyRegex = Regex("[A-Za-z0-9_-]{${cloudStorageKeyLimit.first},${cloudStorageKeyLimit.last}}")
val cloudStorageValueRegex = Regex(".{${cloudStorageValueLimit.first},${cloudStorageValueLimit.last}}")
// Made as lazy for correct work in K/JS
val telegramInlineModeGifPermittedMimeTypes by lazy {
listOf(
@@ -210,10 +215,12 @@ const val firstNameField = "first_name"
const val lastNameField = "last_name"
const val languageCodeField = "language_code"
const val addedToAttachmentMenuField = "added_to_attachment_menu"
const val allowsWriteToPMField = "allows_write_to_pm"
const val isPremiumField = "is_premium"
const val hasPrivateForwardsField = "has_private_forwards"
const val hasRestrictedVoiceAndVideoMessagesField = "has_restricted_voice_and_video_messages"
const val emojiStatusCustomEmojiIdField = "emoji_status_custom_emoji_id"
const val emojiStatusExpirationDateField = "emoji_status_expiration_date"
const val iconCustomEmojiIdField = "icon_custom_emoji_id"
const val canJoinGroupsField = "can_join_groups"
const val canReadAllGroupMessagesField = "can_read_all_group_messages"
@@ -273,6 +280,9 @@ const val correctOptionIdField = "correct_option_id"
const val allowsMultipleAnswersField = "allows_multiple_answers"
const val isAnonymousField = "is_anonymous"
const val canManageTopicsField = "can_manage_topics"
const val canPostStoriesField = "can_post_stories"
const val canEditStoriesField = "can_edit_stories"
const val canDeleteStoriesField = "can_delete_stories"
const val captionEntitiesField = "caption_entities"
const val hasSpoilerField = "has_spoiler"
const val loginUrlField = "login_url"
@@ -289,6 +299,7 @@ const val pinnedMessageField = "pinned_message"
const val activeUsernamesField = "active_usernames"
const val customTitleField = "custom_title"
const val optionIdsField = "option_ids"
const val voterChatField = "voter_chat"
const val ipAddressField = "ip_address"
const val linkedChatIdField = "linked_chat_id"
const val hasHiddenMembersField = "has_hidden_members"

View File

@@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.types.buttons
import dev.inmo.tgbotapi.types.botAdministratorRightsField
import dev.inmo.tgbotapi.types.botIsMemberField
import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights
import dev.inmo.tgbotapi.types.chat.member.ChatCommonAdministratorRights
import dev.inmo.tgbotapi.types.chatHasUsernameField
import dev.inmo.tgbotapi.types.chatIsChannelField
import dev.inmo.tgbotapi.types.chatIsCreatedField
@@ -30,9 +30,9 @@ data class KeyboardButtonRequestChat(
@SerialName(chatIsCreatedField)
val isOwnedBy: Boolean? = null,
@SerialName(userAdministratorRightsField)
val userRightsInChat: ChatAdministratorRights? = null,
val userRightsInChat: ChatCommonAdministratorRights? = null,
@SerialName(botAdministratorRightsField)
val botRightsInChat: ChatAdministratorRights? = null,
val botRightsInChat: ChatCommonAdministratorRights? = null,
@SerialName(botIsMemberField)
val botIsMember: Boolean? = null
) {
@@ -41,8 +41,8 @@ data class KeyboardButtonRequestChat(
requestId: RequestId,
isPublic: Boolean? = null,
isOwnedBy: Boolean? = null,
userRightsInChat: ChatAdministratorRights? = null,
botRightsInChat: ChatAdministratorRights? = null,
userRightsInChat: ChatCommonAdministratorRights? = null,
botRightsInChat: ChatCommonAdministratorRights? = null,
botIsMember: Boolean? = null
) = KeyboardButtonRequestChat(
requestId = requestId,
@@ -60,8 +60,8 @@ data class KeyboardButtonRequestChat(
isForum: Boolean? = null,
isPublic: Boolean? = null,
isOwnedBy: Boolean? = null,
userRightsInChat: ChatAdministratorRights? = null,
botRightsInChat: ChatAdministratorRights? = null,
userRightsInChat: ChatCommonAdministratorRights? = null,
botRightsInChat: ChatCommonAdministratorRights? = null,
botIsMember: Boolean? = null
) = KeyboardButtonRequestChat(
requestId = requestId,

View File

@@ -1,8 +1,7 @@
package dev.inmo.tgbotapi.types.buttons.reply
import dev.inmo.tgbotapi.types.buttons.*
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.*
import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights
import dev.inmo.tgbotapi.types.chat.member.ChatCommonAdministratorRights
import dev.inmo.tgbotapi.types.request.RequestId
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
@@ -120,8 +119,8 @@ inline fun requestChatReplyButton(
isForum: Boolean? = null,
isPublic: Boolean? = null,
isOwnedBy: Boolean? = null,
userRightsInChat: ChatAdministratorRights? = null,
botRightsInChat: ChatAdministratorRights? = null,
userRightsInChat: ChatCommonAdministratorRights? = null,
botRightsInChat: ChatCommonAdministratorRights? = null,
botIsMember: Boolean = false
) = requestChatReplyButton(
text,
@@ -145,8 +144,8 @@ inline fun requestChannelReplyButton(
requestId: RequestId,
isPublic: Boolean? = null,
isOwnedBy: Boolean? = null,
userRightsInChat: ChatAdministratorRights? = null,
botRightsInChat: ChatAdministratorRights? = null,
userRightsInChat: ChatCommonAdministratorRights? = null,
botRightsInChat: ChatCommonAdministratorRights? = null,
botIsMember: Boolean = false
) = requestChatReplyButton(
text,
@@ -170,8 +169,8 @@ inline fun requestChannelReplyButton(
isForum: Boolean? = null,
isPublic: Boolean? = null,
isOwnedBy: Boolean? = null,
userRightsInChat: ChatAdministratorRights? = null,
botRightsInChat: ChatAdministratorRights? = null,
userRightsInChat: ChatCommonAdministratorRights? = null,
botRightsInChat: ChatCommonAdministratorRights? = null,
botIsMember: Boolean? = null
) = requestChatReplyButton(
text,

View File

@@ -4,6 +4,7 @@ import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
import dev.inmo.tgbotapi.utils.RiskFeature
import korlibs.time.DateTime
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonObject
@@ -78,7 +79,9 @@ data class ExtendedPrivateChatImpl(
@SerialName(hasRestrictedVoiceAndVideoMessagesField)
override val hasRestrictedVoiceAndVideoMessages: Boolean = false,
@SerialName(emojiStatusCustomEmojiIdField)
override val statusEmojiId: CustomEmojiId? = null
override val statusEmojiId: CustomEmojiId? = null,
@SerialName(emojiStatusExpirationDateField)
override val statusEmojiExpiration: TelegramDate? = null
) : ExtendedPrivateChat
typealias ExtendedUser = ExtendedPrivateChatImpl

View File

@@ -3,6 +3,7 @@ package dev.inmo.tgbotapi.types.chat
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
import korlibs.time.DateTime
import kotlinx.serialization.Serializable
@Serializable(ExtendedChatSerializer.Companion::class)
@@ -21,6 +22,7 @@ sealed interface ExtendedPrivateChat : PrivateChat, ExtendedChatWithUsername {
val hasPrivateForwards: Boolean
val hasRestrictedVoiceAndVideoMessages: Boolean
val statusEmojiId: CustomEmojiId?
val statusEmojiExpiration: TelegramDate?
val allowCreateUserIdLink: Boolean
get() = hasPrivateForwards

View File

@@ -35,9 +35,16 @@ data class AdministratorChatMemberImpl(
@SerialName(customTitleField)
override val customTitle: String? = null,
@SerialName(canManageTopicsField)
override val canManageTopics: Boolean = false
override val canManageTopics: Boolean = false,
@SerialName(canPostStoriesField)
override val canPostStories: Boolean = false,
@SerialName(canEditStoriesField)
override val canEditStories: Boolean = false,
@SerialName(canDeleteStoriesField)
override val canDeleteStories: Boolean = false
) : AdministratorChatMember {
@SerialName(statusField)
@Required
private val type: String = "administrator"
override val status: ChatMember.Status
get() = ChatMember.Status.Administrator
}

View File

@@ -16,4 +16,43 @@ sealed interface ChatAdministratorRights : SpecialChatAdministratorRights {
val canPromoteMembers: Boolean
val canPostMessages: Boolean
val canEditMessages: Boolean
val canPostStories: Boolean
val canEditStories: Boolean
val canDeleteStories: Boolean
companion object {
operator fun invoke(
canChangeInfo: Boolean = false,
canPostMessages: Boolean = false,
canEditMessages: Boolean = false,
canRemoveMessages: Boolean = false,
canInviteUsers: Boolean = false,
canRestrictMembers: Boolean = false,
canPinMessages: Boolean = false,
canPromoteMembers: Boolean = false,
canManageVideoChats: Boolean = false,
canManageChat: Boolean = false,
isAnonymous: Boolean = false,
canManageTopics: Boolean = false,
canPostStories: Boolean = false,
canEditStories: Boolean = false,
canDeleteStories: Boolean = false
) = ChatCommonAdministratorRights(
canChangeInfo = canChangeInfo,
canPostMessages = canPostMessages,
canEditMessages = canEditMessages,
canRemoveMessages = canRemoveMessages,
canInviteUsers = canInviteUsers,
canRestrictMembers = canRestrictMembers,
canPinMessages = canPinMessages,
canPromoteMembers = canPromoteMembers,
canManageVideoChats = canManageVideoChats,
canManageChat = canManageChat,
isAnonymous = isAnonymous,
canManageTopics = canManageTopics,
canPostStories = canPostStories,
canEditStories = canEditStories,
canDeleteStories = canDeleteStories
)
}
}

View File

@@ -5,7 +5,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class ChatAdministratorRightsImpl(
data class ChatCommonAdministratorRights(
@SerialName(canChangeInfoField)
override val canChangeInfo: Boolean = false,
@SerialName(canPostMessagesField)
@@ -29,5 +29,20 @@ data class ChatAdministratorRightsImpl(
@SerialName(isAnonymousField)
override val isAnonymous: Boolean = false,
@SerialName(canManageTopicsField)
override val canManageTopics: Boolean = false
override val canManageTopics: Boolean = false,
@SerialName(canPostStoriesField)
override val canPostStories: Boolean = false,
@SerialName(canEditStoriesField)
override val canEditStories: Boolean = false,
@SerialName(canDeleteStoriesField)
override val canDeleteStories: Boolean = false
) : ChatAdministratorRights
@Deprecated(
"Renamed to ChatCommonAdministratorRights and will be removed soon",
ReplaceWith(
"ChatCommonAdministratorRights",
"dev.inmo.tgbotapi.types.chat.member.ChatCommonAdministratorRights"
)
)
typealias ChatAdministratorRightsImpl = ChatCommonAdministratorRights

View File

@@ -4,6 +4,7 @@ import dev.inmo.tgbotapi.abstracts.WithUser
import dev.inmo.tgbotapi.types.statusField
import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
@@ -13,7 +14,18 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
@Serializable(ChatMemberSerializer::class)
sealed interface ChatMember : WithUser
sealed interface ChatMember : WithUser {
@Serializable
enum class Status(val status: String, val deserializationStrategy: DeserializationStrategy<ChatMember>) {
Creator("creator", OwnerChatMember.serializer()),
Administrator("administrator", AdministratorChatMemberImpl.serializer()),
Member("member", MemberChatMemberImpl.serializer()),
Restricted("restricted", RestrictedChatMember.serializer()),
Left("left", LeftChatMemberImpl.serializer()),
Kicked("kicked", KickedChatMember.serializer())
}
val status: Status
}
@RiskFeature
object ChatMemberSerializer : KSerializer<ChatMember> {
@@ -21,15 +33,14 @@ object ChatMemberSerializer : KSerializer<ChatMember> {
override fun deserialize(decoder: Decoder): ChatMember {
val json = JsonObject.serializer().deserialize(decoder)
return when (json[statusField] ?.jsonPrimitive ?.content ?: error("Status field of chat member must be specified, but incoming json contains next: $json")) {
"creator" -> nonstrictJsonFormat.decodeFromJsonElement(OwnerChatMember.serializer(), json)
"administrator" -> nonstrictJsonFormat.decodeFromJsonElement(AdministratorChatMemberImpl.serializer(), json)
"member" -> nonstrictJsonFormat.decodeFromJsonElement(MemberChatMemberImpl.serializer(), json)
"restricted" -> nonstrictJsonFormat.decodeFromJsonElement(RestrictedChatMember.serializer(), json)
"left" -> nonstrictJsonFormat.decodeFromJsonElement(LeftChatMemberImpl.serializer(), json)
"kicked" -> nonstrictJsonFormat.decodeFromJsonElement(KickedChatMember.serializer(), json)
else -> error("Unknown type of chat member in json: $json")
}
val status = json[statusField] ?.jsonPrimitive ?.content ?: error("Status field of chat member must be specified, but incoming json contains next: $json")
return ChatMember.Status.values().firstNotNullOfOrNull {
if (it.status == status) {
nonstrictJsonFormat.decodeFromJsonElement(it.deserializationStrategy, json)
} else {
null
}
} ?: error("Unknown type of chat member in json: $json")
}
override fun serialize(encoder: Encoder, value: ChatMember) {

View File

@@ -13,5 +13,6 @@ data class KickedChatMember(
) : BannedChatMember {
@SerialName(statusField)
@Required
private val type: String = "kicked"
override val status: ChatMember.Status
get() = ChatMember.Status.Kicked
}

View File

@@ -5,8 +5,12 @@ import dev.inmo.tgbotapi.types.chat.User
import kotlinx.serialization.*
@Serializable
data class LeftChatMemberImpl(@SerialName(userField) override val user: User) : LeftChatMember {
data class LeftChatMemberImpl(
@SerialName(userField)
override val user: User
) : LeftChatMember {
@SerialName(statusField)
@Required
private val type: String = "left"
override val status: ChatMember.Status
get() = ChatMember.Status.Left
}

View File

@@ -5,8 +5,12 @@ import dev.inmo.tgbotapi.types.chat.User
import kotlinx.serialization.*
@Serializable
data class MemberChatMemberImpl(@SerialName(userField) override val user: User) : MemberChatMember {
data class MemberChatMemberImpl(
@SerialName(userField)
override val user: User
) : MemberChatMember {
@SerialName(statusField)
@Required
private val type: String = "member"
override val status: ChatMember.Status
get() = ChatMember.Status.Member
}

View File

@@ -36,7 +36,15 @@ data class OwnerChatMember(
override val canManageChat: Boolean = true
@Transient
override val canManageTopics: Boolean = true
@Transient
override val canPostStories: Boolean = true
@Transient
override val canEditStories: Boolean = true
@Transient
override val canDeleteStories: Boolean = true
@SerialName(statusField)
@Required
private val type: String = "creator"
override val status: ChatMember.Status
get() = ChatMember.Status.Creator
}

View File

@@ -44,5 +44,6 @@ data class RestrictedChatMember(
) : BannedChatMember, SpecialRightsChatMember, ChatPermissions {
@SerialName(statusField)
@Required
private val type: String = "restricted"
override val status: ChatMember.Status
get() = ChatMember.Status.Restricted
}

View File

@@ -1,12 +1,75 @@
package dev.inmo.tgbotapi.types.message.ChatEvents.forum
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.ChatEvent
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.ForumEvent
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.PrivateEvent
import dev.inmo.tgbotapi.types.webAppNameField
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable
data class WriteAccessAllowed(
@SerialName(webAppNameField)
val webAppName: String? = null
) : ForumEvent
@Serializable(WriteAccessAllowed.Companion::class)
sealed interface WriteAccessAllowed : PrivateEvent, ForumEvent {
val webAppName: String?
get() = null
val fromRequest: Boolean
get() = false
val fromAttachmentMenu: Boolean
get() = false
@Serializable
object Other : WriteAccessAllowed
@Serializable
data class FromWebAppLink(
override val webAppName: String
) : WriteAccessAllowed
@Serializable
object FromRequest : WriteAccessAllowed {
override val fromRequest: Boolean
get() = true
}
@Serializable
object FromAttachmentMenu : WriteAccessAllowed {
override val fromAttachmentMenu: Boolean
get() = true
}
@Serializable
private class WriteAccessAllowedRaw(
val web_app_name: String? = null,
val from_request: Boolean = false,
val from_attachment_menu: Boolean = false
)
companion object : KSerializer<WriteAccessAllowed> {
override val descriptor: SerialDescriptor
get() = WriteAccessAllowedRaw.serializer().descriptor
override fun deserialize(decoder: Decoder): WriteAccessAllowed {
val raw = WriteAccessAllowedRaw.serializer().deserialize(decoder)
return when {
raw.web_app_name != null -> FromWebAppLink(raw.web_app_name)
raw.from_request -> FromRequest
raw.from_attachment_menu -> Other
else -> Other
}
}
override fun serialize(encoder: Encoder, value: WriteAccessAllowed) {
val raw = when (value) {
FromAttachmentMenu -> WriteAccessAllowedRaw(from_attachment_menu = true)
FromRequest -> WriteAccessAllowedRaw(from_request = true)
Other -> WriteAccessAllowedRaw()
is FromWebAppLink -> WriteAccessAllowedRaw(web_app_name = value.webAppName)
}
WriteAccessAllowedRaw.serializer().serialize(encoder, raw)
}
operator fun invoke(webAppName: String?): WriteAccessAllowed = webAppName ?.let(::FromWebAppLink) ?: Other
}
}

View File

@@ -31,6 +31,7 @@ import dev.inmo.tgbotapi.types.payments.SuccessfulPayment
import dev.inmo.tgbotapi.types.polls.Poll
import dev.inmo.tgbotapi.types.request.ChatShared
import dev.inmo.tgbotapi.types.request.UserShared
import dev.inmo.tgbotapi.types.stories.Story
import dev.inmo.tgbotapi.types.venue.Venue
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -65,6 +66,7 @@ internal data class RawMessage(
private val caption: String? = null,
private val caption_entities: RawMessageEntities? = null,
private val has_media_spoiler: Boolean? = null,
private val story: Story? = null,
private val audio: AudioFile? = null,
private val document: DocumentFile? = null,
private val animation: AnimationFile? = null,
@@ -134,6 +136,11 @@ internal data class RawMessage(
} ?: emptyList()
when {
story != null -> StoryContent(
chat,
messageId,
story
)
text != null -> TextContent(text, (entities ?: emptyList()).asTextSources(text))
audio != null -> AudioContent(
audio,

View File

@@ -18,6 +18,30 @@ internal data class RawMessageEntity(
internal val range by lazy {
offset until (offset + length)
}
val priority by lazy {
when (type) {
// Types with potential subsources should have priority
"mention" -> 0
"hashtag" -> 0
"cashtag" -> 0
"email" -> 0
"phone_number" -> 0
"bold" -> 0
"italic" -> 0
"text_mention" -> 0
"strikethrough" -> 0
"underline" -> 0
"spoiler" -> 0
"custom_emoji" -> 0
"bot_command" -> 1
"url" -> 1
"code" -> 1
"pre" -> 1
"text_link" -> 1
else -> 1
}
}
}
internal fun RawMessageEntity.asTextSource(
@@ -85,7 +109,10 @@ private fun createTextSources(
originalFullString: String,
entities: RawMessageEntities
): List<Pair<Int, TextSource>> {
val mutableEntities = entities.toMutableList().apply { sortBy { it.offset } }
val mutableEntities = entities.toMutableList().apply {
sortBy { it.priority } // sorting to fix potential issues in source sorting of entities
sortBy { it.offset }
}
val resultList = mutableListOf<Pair<Int, TextSource>>()
while (mutableEntities.isNotEmpty()) {

View File

@@ -13,8 +13,10 @@ import dev.inmo.tgbotapi.types.media.TelegramMedia
import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.threadId
import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.serialization.Serializable
import kotlinx.serialization.modules.*
@Serializable
sealed interface MessageContent: ResendableContent {
companion object {
@RiskFeature("This serialization module can be changed in near releases")
@@ -49,6 +51,7 @@ sealed interface MessageContent: ResendableContent {
subclass(AnimationContent::class)
subclass(StickerContent::class)
subclass(InvoiceContent::class)
subclass(StoryContent::class)
additionalBuilder()
}

View File

@@ -58,7 +58,6 @@ sealed interface LocationContent : MessageContent {
/**
* [KSerializer] for [LocationContent]
*/
@Serializer(LocationContent::class)
object LocationContentSerializer : KSerializer<LocationContent> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("LocationContent") {
element(LocationContent::location.name, LocationSerializer.descriptor)
@@ -85,7 +84,6 @@ object LocationContentSerializer : KSerializer<LocationContent> {
encodeSerializableElement(descriptor, 0, LocationSerializer, value.location)
}.endStructure(descriptor)
}
}
/**
@@ -94,7 +92,7 @@ object LocationContentSerializer : KSerializer<LocationContent> {
*
* @see dev.inmo.tgbotapi.extensions.behaviour_builder.utils.followLocation
*/
@Serializable(LocationContentSerializer::class)
@Serializable
data class LiveLocationContent(
override val location: LiveLocation
) : LocationContent {
@@ -127,7 +125,7 @@ data class LiveLocationContent(
* Just a [LocationContent] with [StaticLocation] [location]. It could be [LiveLocationContent] in previous time in case
* when somebody has sent [LiveLocation] in chat and then stop to broadcast location
*/
@Serializable(LocationContentSerializer::class)
@Serializable
data class StaticLocationContent(
override val location: StaticLocation
) : LocationContent {

View File

@@ -0,0 +1,38 @@
package dev.inmo.tgbotapi.types.message.content
import dev.inmo.tgbotapi.requests.ForwardMessage
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.MessageId
import dev.inmo.tgbotapi.types.MessageThreadId
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.chat.Chat
import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.stories.Story
import kotlinx.serialization.Serializable
@Serializable
data class StoryContent(
private val chat: Chat,
private val messageId: MessageId,
val story: Story
) : MessageContent {
override fun createResend(
chatId: ChatIdentifier,
messageThreadId: MessageThreadId?,
disableNotification: Boolean,
protectContent: Boolean,
replyToMessageId: MessageId?,
allowSendingWithoutReply: Boolean?,
replyMarkup: KeyboardMarkup?
): Request<out Message> {
return ForwardMessage(
chat.id,
toChatId = chatId,
messageId = messageId,
threadId = messageThreadId,
disableNotification = disableNotification,
protectContent = protectContent
)
}
}

View File

@@ -11,6 +11,7 @@ typealias DiceMessage = CommonMessage<DiceContent>
typealias ContactMessage = CommonMessage<ContactContent>
typealias PollMessage = CommonMessage<PollContent>
typealias TextMessage = CommonMessage<TextContent>
typealias StoryMessage = CommonMessage<StoryContent>
typealias LocationMessage = CommonMessage<LocationContent>
typealias LiveLocationMessage = CommonMessage<LiveLocationContent>

View File

@@ -2,19 +2,95 @@ package dev.inmo.tgbotapi.types.polls
import dev.inmo.tgbotapi.abstracts.FromUser
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.ChannelChat
import dev.inmo.tgbotapi.types.chat.CommonBot
import dev.inmo.tgbotapi.types.chat.User
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable
data class PollAnswer(
@SerialName(pollIdField)
val pollId: PollIdentifier,
@SerialName(userField)
override val user: User,
@SerialName(optionIdsField)
@Serializable(PollAnswer.Companion::class)
sealed interface PollAnswer: FromUser {
val pollId: PollIdentifier
override val user: User
val chosen: List<Int>
) : FromUser {
@Transient
override val from: User
get() = user
@Serializable
data class Public(
@SerialName(pollIdField)
override val pollId: PollIdentifier,
@SerialName(userField)
override val user: User,
@SerialName(optionIdsField)
override val chosen: List<Int>,
) : PollAnswer
@Serializable
data class Anonymous(
@SerialName(pollIdField)
override val pollId: PollIdentifier,
@SerialName(voterChatField)
val voterChat: ChannelChat,
@SerialName(optionIdsField)
override val chosen: List<Int>
) : PollAnswer {
@SerialName(userField)
override val user: User = defaultUser
companion object {
val defaultUser = CommonBot(
UserId(136817688L),
"",
"",
Username("@Channel_Bot")
)
}
}
companion object : KSerializer<PollAnswer> {
@Serializable
private data class PollAnswerSurrogate(
@SerialName(pollIdField)
val pollId: PollIdentifier,
@SerialName(optionIdsField)
val chosen: List<Int>,
@SerialName(userField)
val user: User = Anonymous.defaultUser,
@SerialName(voterChatField)
val voterChat: ChannelChat? = null
)
operator fun invoke(
pollId: PollIdentifier,
user: User,
chosen: List<Int>,
) = Public(pollId, user, chosen)
override val descriptor: SerialDescriptor
get() = PollAnswerSurrogate.serializer().descriptor
override fun deserialize(decoder: Decoder): PollAnswer {
val surrogate = PollAnswerSurrogate.serializer().deserialize(decoder)
return if (surrogate.voterChat != null) {
Anonymous(surrogate.pollId, surrogate.voterChat, surrogate.chosen)
} else {
Public(surrogate.pollId, surrogate.user, surrogate.chosen)
}
}
override fun serialize(encoder: Encoder, value: PollAnswer) {
PollAnswerSurrogate.serializer().serialize(
encoder,
PollAnswerSurrogate(
value.pollId,
value.chosen,
value.user,
(value as? Anonymous) ?.voterChat
)
)
}
}
}

View File

@@ -7,8 +7,9 @@ import kotlin.random.Random
@Serializable
@JvmInline
value class RequestId(
val int: Int
val uShort: UShort
) {
constructor(int: Int) : this(int.toUShort())
companion object {
fun random() = RequestId(Random.nextInt())
}

View File

@@ -0,0 +1,6 @@
package dev.inmo.tgbotapi.types.stories
import kotlinx.serialization.Serializable
@Serializable
class Story

View File

@@ -292,6 +292,7 @@ import dev.inmo.tgbotapi.types.message.content.ResendableContent
import dev.inmo.tgbotapi.types.message.content.SpoilerableMediaContent
import dev.inmo.tgbotapi.types.message.content.StaticLocationContent
import dev.inmo.tgbotapi.types.message.content.StickerContent
import dev.inmo.tgbotapi.types.message.content.StoryContent
import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.types.message.content.TextedContent
import dev.inmo.tgbotapi.types.message.content.TextedMediaContent
@@ -3480,6 +3481,15 @@ public inline fun ResendableContent.stickerContentOrThrow(): StickerContent = th
public inline fun <T> ResendableContent.ifStickerContent(block: (StickerContent) -> T): T? =
stickerContentOrNull() ?.let(block)
public inline fun ResendableContent.storyContentOrNull(): StoryContent? = this as?
dev.inmo.tgbotapi.types.message.content.StoryContent
public inline fun ResendableContent.storyContentOrThrow(): StoryContent = this as
dev.inmo.tgbotapi.types.message.content.StoryContent
public inline fun <T> ResendableContent.ifStoryContent(block: (StoryContent) -> T): T? =
storyContentOrNull() ?.let(block)
public inline fun ResendableContent.textContentOrNull(): TextContent? = this as?
dev.inmo.tgbotapi.types.message.content.TextContent

View File

@@ -21,6 +21,7 @@ fun Flow<ContentMessage<*>>.onlyPhotoContentMessages() = withContentType<PhotoCo
fun Flow<ContentMessage<*>>.onlyPollContentMessages() = withContentType<PollContent>()
fun Flow<ContentMessage<*>>.onlyStickerContentMessages() = withContentType<StickerContent>()
fun Flow<ContentMessage<*>>.onlyTextContentMessages() = withContentType<TextContent>()
fun Flow<ContentMessage<*>>.onlyStoryContentMessages() = withContentType<StoryContent>()
fun Flow<ContentMessage<*>>.onlyVenueContentMessages() = withContentType<VenueContent>()
fun Flow<ContentMessage<*>>.onlyVideoContentMessages() = withContentType<VideoContent>()
fun Flow<ContentMessage<*>>.onlyVideoNoteContentMessages() = withContentType<VideoNoteContent>()

View File

@@ -120,6 +120,11 @@ fun FlowsUpdatesFilter.textMessages(
scopeToIncludeChannels: CoroutineScope? = null
) = filterContentMessages<TextContent>(scopeToIncludeChannels)
fun Flow<BaseSentMessageUpdate>.storyMessages() = filterContentMessages<StoryContent>()
fun FlowsUpdatesFilter.storyMessages(
scopeToIncludeChannels: CoroutineScope? = null
) = filterContentMessages<StoryContent>(scopeToIncludeChannels)
fun Flow<BaseSentMessageUpdate>.venueMessages() = filterContentMessages<VenueContent>()
fun FlowsUpdatesFilter.venueMessages(
scopeToIncludeChannels: CoroutineScope? = null

View File

@@ -3,7 +3,7 @@ package dev.inmo.tgbotapi.extensions.utils.types.buttons
import dev.inmo.tgbotapi.types.buttons.*
import dev.inmo.tgbotapi.types.buttons.reply.requestChatReplyButton
import dev.inmo.tgbotapi.types.buttons.reply.requestUserReplyButton
import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights
import dev.inmo.tgbotapi.types.chat.member.ChatCommonAdministratorRights
import dev.inmo.tgbotapi.types.request.RequestId
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
import dev.inmo.tgbotapi.utils.*
@@ -220,8 +220,8 @@ inline fun ReplyKeyboardRowBuilder.requestChatButton(
isForum: Boolean? = null,
isPublic: Boolean? = null,
isOwnedBy: Boolean? = null,
userRightsInChat: ChatAdministratorRights? = null,
botRightsInChat: ChatAdministratorRights? = null,
userRightsInChat: ChatCommonAdministratorRights? = null,
botRightsInChat: ChatCommonAdministratorRights? = null,
botIsMember: Boolean? = null
) = requestChatButton(
text,
@@ -248,8 +248,8 @@ inline fun ReplyKeyboardRowBuilder.requestChannelButton(
requestId: RequestId,
isPublic: Boolean? = null,
isOwnedBy: Boolean? = null,
userRightsInChat: ChatAdministratorRights? = null,
botRightsInChat: ChatAdministratorRights? = null,
userRightsInChat: ChatCommonAdministratorRights? = null,
botRightsInChat: ChatCommonAdministratorRights? = null,
botIsMember: Boolean? = null
) = requestChatButton(
text,
@@ -275,8 +275,8 @@ inline fun ReplyKeyboardRowBuilder.requestGroupButton(
isForum: Boolean? = null,
isPublic: Boolean? = null,
isOwnedBy: Boolean? = null,
userRightsInChat: ChatAdministratorRights? = null,
botRightsInChat: ChatAdministratorRights? = null,
userRightsInChat: ChatCommonAdministratorRights? = null,
botRightsInChat: ChatCommonAdministratorRights? = null,
botIsMember: Boolean? = null
) = requestChatButton(
text,

View File

@@ -8,7 +8,9 @@ sealed interface Color {
value class BackgroundColor(override val value: String) : Color
@Serializable
value class Hex(override val value: String) : Color
value class Hex(override val value: String) : Color {
constructor(r: UByte, g: UByte, b: UByte) : this("#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}")
}
companion object {
val BackgroundColor = BackgroundColor("bg_color")

View File

@@ -8,3 +8,5 @@ typealias InvoiceClosedEventHandler = WebApp.(InvoiceClosedInfo) -> Unit
typealias PopupClosedEventHandler = WebApp.(String?) -> Unit
typealias QRTextReceivedEventHandler = WebApp.(String) -> Boolean
typealias TextReceivedEventHandler = WebApp.(String) -> Unit
typealias WriteAccessRequestedHandler = WebApp.(Boolean) -> Unit
typealias ContactRequestedHandler = WebApp.(Boolean) -> Unit

View File

@@ -10,4 +10,6 @@ sealed class EventType(val typeName: String) {
object PopupClosed : EventType("popupClosed")
object QRTextReceived : EventType("qrTextReceived")
object ClipboardTextReceived : EventType("clipboardTextReceived")
object WriteAccessRequested : EventType("writeAccessRequested")
object ContactRequested : EventType("contactRequested")
}

View File

@@ -0,0 +1,14 @@
package dev.inmo.tgbotapi.webapps
external interface RequestStatus {
val status: String
}
inline val RequestStatus.isCancelled: Boolean
get() = status == "cancelled"
inline val RequestStatus.isAllowed: Boolean
get() = status == "allowed"
inline val RequestStatus.isSent: Boolean
get() = status == "sent"

View File

@@ -1,9 +1,11 @@
package dev.inmo.tgbotapi.webapps
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.webapps.cloud.CloudStorage
import dev.inmo.tgbotapi.webapps.haptic.HapticFeedback
import dev.inmo.tgbotapi.webapps.invoice.InvoiceClosedInfo
import dev.inmo.tgbotapi.webapps.popup.*
import kotlin.js.Json
external class WebApp {
val version: String
@@ -15,6 +17,7 @@ external class WebApp {
val headerColor: HEXColor?
fun setHeaderColor(color: Color.BackgroundColor)
fun setHeaderColor(color: Color.Hex)
val backgroundColor: HEXColor?
fun setBackgroundColor(color: Color.Hex)
fun setBackgroundColor(color: Color.BackgroundColor)
@@ -48,6 +51,9 @@ external class WebApp {
@JsName("HapticFeedback")
val hapticFeedback: HapticFeedback
@JsName("CloudStorage")
val cloudStorage: CloudStorage
internal fun onEvent(type: String, callback: () -> Unit)
@JsName("onEvent")
internal fun onEventWithViewportChangedData(type: String, callback: (ViewportChangedData) -> Unit)
@@ -59,6 +65,10 @@ external class WebApp {
internal fun onEventWithQRTextInfo(type: String, callback: (String) -> Boolean)
@JsName("onEvent")
internal fun onEventWithTextInfo(type: String, callback: (String) -> Unit)
@JsName("onEvent")
internal fun onEventWithWriteAccessRequested(type: String, callback: (RequestStatus) -> Unit)
@JsName("onEvent")
internal fun onEventWithContactRequested(type: String, callback: (RequestStatus) -> Unit)
fun offEvent(type: String, callback: () -> Unit)
@JsName("offEvent")
@@ -76,6 +86,9 @@ external class WebApp {
fun openLink(url: String)
fun openTelegramLink(url: String)
fun openInvoice(url: String, callback: (InvoiceClosedInfo) -> Unit = definedExternally)
fun requestWriteAccess(callback: ((Boolean) -> Unit)? = definedExternally)
fun requestContact(callback: ((Boolean) -> Unit)? = definedExternally)
}
val WebApp.colorScheme: ColorScheme
@@ -157,6 +170,30 @@ fun WebApp.onEvent(type: EventType.ClipboardTextReceived, eventHandler: TextRece
)
}
/**
* @return The callback which should be used in case you want to turn off events handling
*/
fun WebApp.onEvent(type: EventType.WriteAccessRequested, eventHandler: WriteAccessRequestedHandler) = { it: RequestStatus ->
eventHandler(js("this").unsafeCast<WebApp>(), it.isAllowed)
}.also {
onEventWithWriteAccessRequested(
type.typeName,
callback = it
)
}
/**
* @return The callback which should be used in case you want to turn off events handling
*/
fun WebApp.onEvent(type: EventType.ContactRequested, eventHandler: ContactRequestedHandler) = { it: RequestStatus ->
eventHandler(js("this").unsafeCast<WebApp>(), it.isSent)
}.also {
onEventWithContactRequested(
type.typeName,
callback = it
)
}
/**
* @return The callback which should be used in case you want to turn off events handling
*/
@@ -193,6 +230,14 @@ fun WebApp.onQRTextReceived(eventHandler: QRTextReceivedEventHandler) = onEvent(
* @return The callback which should be used in case you want to turn off events handling
*/
fun WebApp.onClipboardTextReceived(eventHandler: TextReceivedEventHandler) = onEvent(EventType.ClipboardTextReceived, eventHandler)
/**
* @return The callback which should be used in case you want to turn off events handling
*/
fun WebApp.onWriteAccessRequested(eventHandler: WriteAccessRequestedHandler) = onEvent(EventType.WriteAccessRequested, eventHandler)
/**
* @return The callback which should be used in case you want to turn off events handling
*/
fun WebApp.onContactRequested(eventHandler: ContactRequestedHandler) = onEvent(EventType.ContactRequested, eventHandler)
fun WebApp.isInitDataSafe(botToken: String) = TelegramAPIUrlsKeeper(botToken).checkWebAppData(
initData,

View File

@@ -20,6 +20,10 @@ external interface WebAppUser {
val is_premium: Boolean?
@JsName(photoUrlField)
val photoUrl: String?
@JsName(addedToAttachmentMenuField)
val addedToAttachmentMenu: Boolean?
@JsName(allowsWriteToPMField)
val allowsWriteToPM: Boolean?
}
val WebAppUser.isPremium

View File

@@ -0,0 +1,139 @@
package dev.inmo.tgbotapi.webapps.cloud
import kotlin.js.Json
external interface CloudStorage {
fun setItem(
key: CloudStorageKey,
value: CloudStorageValue,
callback: (e: Any?, success: Boolean?) -> Unit = definedExternally
): CloudStorage
fun getItem(
key: CloudStorageKey,
callback: (e: Any?, value: CloudStorageValue?) -> Unit
): CloudStorage
fun getItems(
key: Array<CloudStorageKey>,
callback: (e: Any?, values: Array<CloudStorageValue>?) -> Unit
): CloudStorage
fun removeItem(
key: CloudStorageKey,
callback: (e: Any?, success: Boolean?) -> Unit
): CloudStorage
fun removeItems(
key: Array<CloudStorageKey>,
callback: (e: Any?, success: Boolean?) -> Unit
): CloudStorage
fun getKeys(
callback: (e: Any?, success: Array<CloudStorageKey>?) -> Unit
): CloudStorage
}
private fun <T> resultsToResult(e: Any?, v: T?): Result<T> = when {
e != null -> Result.failure(IllegalStateException(JSON.stringify(e)))
v != null -> Result.success(v)
else -> Result.failure(IllegalStateException("Both value and e"))
}
fun CloudStorage.set(
key: String,
value: String,
callback: (result: Result<Boolean>) -> Unit = {}
) = setItem(CloudStorageKey(key), CloudStorageValue(value)) { e, v -> callback(resultsToResult(e, v)) }
fun CloudStorage.get(
key: CloudStorageKey,
callback: (result: Result<CloudStorageValue>) -> Unit
) = getItem(key) { e, v -> callback(resultsToResult(e, v)) }
fun CloudStorage.get(
key: String,
callback: (result: Result<CloudStorageValue>) -> Unit
) = get(CloudStorageKey(key), callback)
fun CloudStorage.get(
keys: Array<CloudStorageKey>,
callback: (result: Result<Array<CloudStorageValue>>) -> Unit
) = getItems(
keys
) { e, v -> callback(resultsToResult(e, v)) }
fun CloudStorage.get(
keys: Array<String>,
callback: (result: Result<Array<CloudStorageValue>>) -> Unit
) = get(
Array(keys.size) {
CloudStorageKey(keys[it])
},
callback
)
fun CloudStorage.get(
key: String,
key2: String,
vararg otherKeys: String,
callback: (result: Result<Array<CloudStorageValue>>) -> Unit
) = get(
arrayOf(key, key2) + otherKeys,
callback
)
fun CloudStorage.remove(
key: CloudStorageKey,
callback: (result: Result<Boolean>) -> Unit
) = removeItem(key) { e, v -> callback(resultsToResult(e, v)) }
fun CloudStorage.remove(
key: String,
callback: (result: Result<Boolean>) -> Unit
) = remove(CloudStorageKey(key), callback)
fun CloudStorage.remove(
keys: Array<CloudStorageKey>,
callback: (result: Result<Boolean>) -> Unit
) = removeItems(
keys
) { e, v -> callback(resultsToResult(e, v)) }
fun CloudStorage.remove(
keys: Array<String>,
callback: (result: Result<Boolean>) -> Unit
) = remove(
Array(keys.size) {
CloudStorageKey(keys[it])
},
callback
)
fun CloudStorage.remove(
key: String,
key2: String,
vararg otherKeys: String,
callback: (result: Result<Boolean>) -> Unit
) = remove(
arrayOf(key, key2) + otherKeys,
callback
)
fun CloudStorage.keys(
callback: (result: Result<Array<CloudStorageKey>>) -> Unit
) = getKeys { e, v -> callback(resultsToResult(e, v)) }
fun CloudStorage.getAll(callback: (result: Result<Map<CloudStorageKey, CloudStorageValue>>) -> Unit) = keys {
it.onSuccess { keys ->
console.log(keys)
get(keys) {
it.onSuccess { values ->
console.log(values)
val resultMap = keys.withIndex().mapNotNull { (i, it) ->
it to (values.getOrNull(i) ?: return@mapNotNull null)
}.toMap()
callback(Result.success(resultMap))
}.onFailure {
callback(Result.failure(it))
}
}
}.onFailure {
callback(Result.failure(it))
}
}

View File

@@ -0,0 +1,13 @@
package dev.inmo.tgbotapi.webapps.cloud
import dev.inmo.tgbotapi.types.cloudStorageKeyRegex
import kotlinx.serialization.Serializable
@Serializable
value class CloudStorageKey(val key: String) {
init {
require(key.matches(cloudStorageKeyRegex)) {
"'$key' must pass $cloudStorageKeyRegex in case you wish to use it as key for cloud storage operations"
}
}
}

View File

@@ -0,0 +1,14 @@
package dev.inmo.tgbotapi.webapps.cloud
import dev.inmo.tgbotapi.types.cloudStorageKeyRegex
import dev.inmo.tgbotapi.types.cloudStorageValueRegex
import kotlinx.serialization.Serializable
@Serializable
value class CloudStorageValue(val value: String) {
init {
require(value.matches(cloudStorageValueRegex)) {
"'$value' must pass $cloudStorageValueRegex in case you wish to use it as key for cloud storage operations"
}
}
}