Compare commits

...

15 Commits

Author SHA1 Message Date
9a4bd55ef6 update tgbotapi version 2022-05-17 19:55:42 +06:00
4dac411693 add support of data checking in webapp 2022-05-17 18:58:43 +06:00
d386d50f1c Merge pull request #107 from InsanusMokrassar/renovate/telegram_bot_api_version
Update telegram_bot_api_version to v1.1.0
2022-05-14 17:33:30 +06:00
Renovate Bot
1b846a6383 Update telegram_bot_api_version to v1.1.0 2022-05-14 11:33:22 +00:00
568b845890 Merge pull request #106 from InsanusMokrassar/renovate/micro_utils_version
Update dependency dev.inmo:micro_utils.ktor.server to v0.10.4
2022-05-14 17:32:48 +06:00
Renovate Bot
3ebca4a058 Update dependency dev.inmo:micro_utils.ktor.server to v0.10.4 2022-05-12 15:37:39 +00:00
2b9af2f667 Merge pull request #104 from InsanusMokrassar/1.0.0
1.0.0
2022-05-12 17:05:10 +06:00
16410debff decrease xmx 2022-05-12 17:00:22 +06:00
a18f22fe8f update xmx for builds 2022-05-12 16:47:46 +06:00
0489f217b3 update examples 2022-05-11 12:15:18 +06:00
e772cfda3b start migration onto 1.0.0 2022-05-11 02:47:37 +06:00
9d42385662 1.0.0 migration preview 2022-05-11 00:23:14 +06:00
b740203116 0.38.23 2022-05-08 00:41:13 +06:00
149717301d Update gradle.properties 2022-05-05 15:16:24 +06:00
60e72be844 Merge pull request #103 from InsanusMokrassar/0.38.21
0.38.21
2022-05-04 14:54:45 +06:00
18 changed files with 156 additions and 73 deletions

View File

@@ -8,9 +8,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 1.8
java-version: 11
- name: Build with Gradle
run: ./gradlew build

View File

@@ -1,3 +1,4 @@
import dev.inmo.micro_utils.coroutines.AccumulatorFlow
import dev.inmo.micro_utils.fsm.common.State
import dev.inmo.tgbotapi.extensions.api.send.sendMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.*

View File

@@ -1,7 +1,6 @@
import dev.inmo.tgbotapi.extensions.api.files.downloadFile
import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviour
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMedia

View File

@@ -2,7 +2,9 @@ import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.utils.formatting.*
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.CommonBot
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.chat.ExtendedBot
import dev.inmo.tgbotapi.types.message.*
import kotlinx.coroutines.*
@@ -34,8 +36,6 @@ suspend fun main(vararg args: String) {
}
}
reply(it, toAnswer)
coroutineContext.job.invokeOnCompletion { println("completance of onContentMessage") }
}
coroutineContext.job.invokeOnCompletion { println("Completed :)") }
}.second.join()
}

View File

@@ -1,4 +1,4 @@
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.bot.getMe
/**
@@ -10,4 +10,4 @@ suspend fun main(vararg args: String) {
val bot = telegramBot(botToken)
println(bot.getMe())
}
}

View File

@@ -6,15 +6,19 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAn
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
import dev.inmo.tgbotapi.types.User
import dev.inmo.tgbotapi.types.chat.abstracts.*
import dev.inmo.tgbotapi.types.chat.*
import dev.inmo.tgbotapi.types.chat.GroupChat
import dev.inmo.tgbotapi.types.chat.PrivateChat
import dev.inmo.tgbotapi.types.chat.SupergroupChat
import dev.inmo.tgbotapi.types.message.MarkdownV2
import dev.inmo.tgbotapi.utils.PreviewFeature
import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common
import kotlinx.coroutines.*
/**
* The main purpose of this bot is just to answer "Oh, hi, " and add user mention here
*/
@OptIn(PreviewFeature::class)
suspend fun main(vararg args: String) {
val botToken = args.first()
@@ -27,8 +31,8 @@ suspend fun main(vararg args: String) {
return@onContentMessage
}
val answerText = "Oh, hi, " + when (chat) {
is PrivateChat -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
is User -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
is PrivateChat -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
is SupergroupChat -> (chat.username ?.username ?: getChat(chat).inviteLink) ?.let {
chat.title.linkMarkdownV2(it)
} ?: chat.title

View File

@@ -9,7 +9,7 @@ buildscript {
}
plugins {
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
id "org.jetbrains.kotlin.multiplatform"
}

View File

@@ -1,17 +1,17 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.answers.answer
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText
import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.send.media.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.CommonMessageFilterExcludeMediaGroups
import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.MessageFilterByChat
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.shortcuts.*
import dev.inmo.tgbotapi.extensions.utils.formatting.botCommand
import dev.inmo.tgbotapi.extensions.utils.formatting.buildEntities
import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.extensions.utils.withContent
import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.message.content.TextContent
import kotlinx.coroutines.*
@@ -86,12 +86,14 @@ suspend fun activateKeyboardsBot(
return@onMessageDataCallbackQuery
}
val text = "This is $page of $count"
editMessageText(
it.message.withContent<TextContent>() ?: it.let {
answer(it, "Unsupported message type :(")
return@onMessageDataCallbackQuery
},
"This is $page of $count",
text,
replyMarkup = inlineKeyboard {
row {
includePageButtons(page, count)
@@ -100,6 +102,22 @@ suspend fun activateKeyboardsBot(
)
}
onUnhandledCommand {
reply(
it,
buildEntities {
+"Use " + botCommand("inline") + " to get pagination inline keyboard"
},
replyMarkup = replyKeyboard(resizeKeyboard = true, oneTimeKeyboard = true) {
row {
simpleButton("/inline")
}
}
)
}
setMyCommands(BotCommand("inline", "Creates message with pagination inline keyboard"))
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
println(it)
}

View File

@@ -1,4 +1,4 @@
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
@@ -6,18 +6,13 @@ import dev.inmo.tgbotapi.extensions.api.send.media.sendDocument
import dev.inmo.tgbotapi.extensions.api.send.media.sendDocumentsGroup
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.withUploadDocumentAction
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviour
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommandWithArgs
import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
import dev.inmo.tgbotapi.requests.abstracts.toInputFile
import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.InputMedia.DocumentMediaGroupMemberInputMedia
import dev.inmo.tgbotapi.types.InputMedia.InputMediaDocument
import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.chat.Chat
import dev.inmo.tgbotapi.types.media.TelegramMediaDocument
import dev.inmo.tgbotapi.types.mediaCountInMediaGroup
import kotlinx.coroutines.*
import java.io.File
private const val command = "send_file"
@@ -50,7 +45,7 @@ suspend fun main(args: Array<String>) {
)
else -> sendDocumentsGroup(
chat,
files.map { InputMediaDocument(it.asMultipartFile()) },
files.map { TelegramMediaDocument(it.asMultipartFile()) },
protectContent = true
)
}

View File

@@ -9,7 +9,7 @@ buildscript {
}
plugins {
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
id "org.jetbrains.kotlin.multiplatform"
}

View File

@@ -1,6 +1,6 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.send.media.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
@@ -8,7 +8,6 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.CommonMessageFilte
import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.MessageFilterByChat
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.shortcuts.*
import dev.inmo.tgbotapi.types.message.abstracts.Message
import kotlinx.coroutines.*
suspend fun activateResenderBot(
@@ -32,19 +31,19 @@ suspend fun activateResenderBot(
onVisualGallery {
val chat = it.chat ?: return@onVisualGallery
withUploadPhotoAction(chat) {
sendVisualMediaGroup(chat, it.map { it.content.toMediaGroupMemberInputMedia() })
sendVisualMediaGroup(chat, it.map { it.content.toMediaGroupMemberTelegramMedia() })
}
}
onPlaylist {
val chat = it.chat ?: return@onPlaylist
withUploadDocumentAction(chat) {
sendPlaylist(chat, it.map { it.content.toMediaGroupMemberInputMedia() })
sendPlaylist(chat, it.map { it.content.toMediaGroupMemberTelegramMedia() })
}
}
onDocumentsGroup {
val chat = it.chat ?: return@onDocumentsGroup
withUploadDocumentAction(chat) {
sendDocumentsGroup(chat, it.map { it.content.toMediaGroupMemberInputMedia() })
sendDocumentsGroup(chat, it.map { it.content.toMediaGroupMemberTelegramMedia() })
}
}

View File

@@ -1,35 +1,26 @@
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onDice
import dev.inmo.tgbotapi.extensions.utils.*
import dev.inmo.tgbotapi.extensions.utils.shortcuts.filterContentMessages
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling
import dev.inmo.tgbotapi.types.dice.SlotMachineDiceAnimationType
import dev.inmo.tgbotapi.types.message.content.DiceContent
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
suspend fun main(args: Array<String>) {
val bot = telegramBot(args.first())
val scope = CoroutineScope(Dispatchers.Default)
bot.longPolling(scope = scope) {
filterContentMessages<DiceContent>(scope).onEach {
bot.buildBehaviourWithLongPolling(scope = CoroutineScope(Dispatchers.IO)) {
onDice {
val content = it.content
val dice = content.dice
val diceType = dice.animationType
safely ({ it.printStackTrace() }) {
if (diceType == SlotMachineDiceAnimationType) {
val result = dice.calculateSlotMachineResult() ?: return@safely
bot.reply(it, "${result.leftReel}|${result.centerReel}|${result.rightReel}")
} else {
bot.reply(it, "There is no slot machine dice in message")
}
if (diceType == SlotMachineDiceAnimationType) {
val result = dice.calculateSlotMachineResult() ?: return@onDice
bot.reply(it, "${result.leftReel}|${result.centerReel}|${result.rightReel}")
} else {
bot.reply(it, "There is no slot machine dice in message")
}
}.launchIn(scope)
}
scope.coroutineContext[Job]!!.join()
}
}
}.join()
}

View File

@@ -9,7 +9,8 @@ buildscript {
}
plugins {
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply plugin: 'application'
@@ -25,6 +26,7 @@ kotlin {
commonMain {
dependencies {
implementation kotlin('stdlib')
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version"
}
}

View File

@@ -0,0 +1,7 @@
import kotlinx.serialization.Serializable
@Serializable
data class WebAppDataWrapper(
val data: String,
val hash: String
)

View File

@@ -2,10 +2,8 @@ import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
import dev.inmo.tgbotapi.types.webAppQueryIdField
import dev.inmo.tgbotapi.webapps.*
import io.ktor.client.HttpClient
import io.ktor.client.call.receive
import io.ktor.client.request.*
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.readText
import io.ktor.client.statement.bodyAsText
import io.ktor.http.*
import io.ktor.http.content.TextContent
import kotlinx.browser.document
@@ -13,6 +11,7 @@ import kotlinx.browser.window
import kotlinx.coroutines.*
import kotlinx.dom.appendElement
import kotlinx.dom.appendText
import kotlinx.serialization.json.Json
import org.w3c.dom.HTMLElement
fun HTMLElement.log(text: String) {
@@ -22,16 +21,40 @@ fun HTMLElement.log(text: String) {
fun main() {
console.log("Web app started")
val client = HttpClient()
val baseUrl = window.location.origin.removeSuffix("/")
window.onload = {
val scope = CoroutineScope(Dispatchers.Default)
runCatching {
scope.launchSafelyWithoutExceptions {
val response = client.post("$baseUrl/check") {
setBody(
Json { }.encodeToString(
WebAppDataWrapper.serializer(),
WebAppDataWrapper(webApp.initData, webApp.initDataUnsafe.hash)
)
)
}
val dataIsSafe = response.bodyAsText().toBoolean()
document.body ?.appendElement("div") {
textContent = if (dataIsSafe) {
"Data is safe"
} else {
"Data is unsafe"
}
}
}
document.body ?.appendElement("button") {
addEventListener("click", {
scope.launchSafelyWithoutExceptions {
handleResult({ "Clicked" }) {
HttpClient().post<HttpResponse>("${window.location.origin.removeSuffix("/")}/inline") {
client.post("${window.location.origin.removeSuffix("/")}/inline") {
parameter(webAppQueryIdField, it)
body = TextContent("Clicked", ContentType.Text.Plain)
setBody(TextContent("Clicked", ContentType.Text.Plain))
document.body ?.log(url.build().toString())
}.coroutineContext.job.join()
}

View File

@@ -1,4 +1,5 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.micro_utils.crypto.hmacSha256
import dev.inmo.micro_utils.ktor.server.createKtorServer
import dev.inmo.tgbotapi.extensions.api.answers.answer
import dev.inmo.tgbotapi.extensions.api.bot.getMe
@@ -7,20 +8,27 @@ import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.telegramBot
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.formatting.botCommand
import dev.inmo.tgbotapi.extensions.utils.formatting.buildEntities
import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent
import dev.inmo.tgbotapi.types.webAppQueryIdField
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
import io.ktor.application.call
import io.ktor.http.HttpStatusCode
import io.ktor.http.content.*
import io.ktor.request.receiveText
import io.ktor.response.respond
import io.ktor.routing.*
import dev.inmo.tgbotapi.utils.PreviewFeature
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import io.ktor.http.*
import io.ktor.server.application.call
import io.ktor.server.http.content.*
import io.ktor.server.request.receiveText
import io.ktor.server.response.respond
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
import kotlinx.coroutines.Dispatchers
import kotlinx.serialization.json.Json
import java.io.File
import java.nio.charset.Charset
/**
* Accepts two parameters:
@@ -30,8 +38,13 @@ import java.io.File
*
* Will start the server to share the static (index.html and WebApp.js) on 0.0.0.0:8080
*/
@OptIn(PreviewFeature::class)
suspend fun main(vararg args: String) {
val bot = telegramBot(args.first(), testServer = args.any { it == "testServer" })
val telegramBotAPIUrlsKeeper = TelegramAPIUrlsKeeper(
args.first(),
testServer = args.any { it == "testServer" }
)
val bot = telegramBot(telegramBotAPIUrlsKeeper)
createKtorServer(
"0.0.0.0",
8080,
@@ -51,6 +64,14 @@ suspend fun main(vararg args: String) {
bot.answer(queryId, InlineQueryResultArticle(queryId, "Result", InputTextMessageContent(requestBody)))
call.respond(HttpStatusCode.OK)
}
post("check") {
val requestBody = call.receiveText()
val webAppCheckData = Json { }.decodeFromString(WebAppDataWrapper.serializer(), requestBody)
val isSafe = telegramBotAPIUrlsKeeper.checkWebAppLink(webAppCheckData.data, webAppCheckData.hash)
call.respond(HttpStatusCode.OK, isSafe.toString())
}
}
}.start(false)
@@ -81,6 +102,15 @@ suspend fun main(vararg args: String) {
)
}
onUnhandledCommand {
reply(
it,
buildEntities {
+"Use " + botCommand("inline") + " to get inline web app button\n"
+"Use " + botCommand("reply_markup") + " to get reply markup web app button\n"
}
)
}
setMyCommands(
BotCommand("reply_markup", "Use to get reply markup keyboard with web app trigger"),
BotCommand("inline", "Use to get inline keyboard with web app trigger"),

View File

@@ -1,3 +1,14 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
}
}
allprojects {
repositories {
mavenLocal()

View File

@@ -1,8 +1,11 @@
kotlin.code.style=official
org.gradle.parallel=true
# Due to parallel compilation project require next amount of memory on full build
org.gradle.jvmargs=-Xmx768m
kotlin_version=1.6.10
telegram_bot_api_version=0.38.21
micro_utils_version=0.9.24
ktor_version=1.6.8
kotlin_version=1.6.21
telegram_bot_api_version=1.1.1
micro_utils_version=0.10.4
serialization_version=1.3.3
ktor_version=2.0.1