Compare commits

..

1 Commits

Author SHA1 Message Date
Renovate Bot
382a8757f1 Update plugin org.jetbrains.kotlin.multiplatform to v1.6.21 2022-04-26 09:48:39 +00:00
29 changed files with 88 additions and 459 deletions

View File

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

View File

@@ -1,6 +1,4 @@
import dev.inmo.micro_utils.coroutines.AccumulatorFlow
import dev.inmo.micro_utils.fsm.common.State
import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.api.send.sendMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.*
@@ -11,7 +9,6 @@ import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.message.content.TextContent
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.first
sealed interface BotState : State
data class ExpectContentOrStopState(override val context: ChatId, val sourceMessage: CommonMessage<TextContent>) : BotState
@@ -20,22 +17,7 @@ data class StopState(override val context: ChatId) : BotState
suspend fun main(args: Array<String>) {
val botToken = args.first()
telegramBotWithBehaviourAndFSMAndStartLongPolling<BotState>(
botToken,
CoroutineScope(Dispatchers.IO),
onStateHandlingErrorHandler = { state, e ->
when (state) {
is ExpectContentOrStopState -> {
println("Thrown error on ExpectContentOrStopState")
}
is StopState -> {
println("Thrown error on StopState")
}
}
e.printStackTrace()
state
}
) {
telegramBotWithBehaviourAndFSMAndStartLongPolling<BotState>(botToken, CoroutineScope(Dispatchers.IO)) {
strictlyOn<ExpectContentOrStopState> {
sendMessage(
it.context,
@@ -56,7 +38,7 @@ suspend fun main(args: Array<String>) {
}
}
strictlyOn<StopState> {
send(it.context, "You have stopped sending of content")
sendMessage(it.context, "You have stopped sending of content")
null
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {

View File

@@ -1,6 +1,7 @@
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
@@ -20,9 +21,11 @@ suspend fun main(args: Array<String>) {
telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) {
onMedia(initialFilter = null) {
val pathedFile = bot.getFileAdditionalInfo(it.content.media)
val outFile = File(directoryOrFile, pathedFile.filePath.filenameFromUrl)
bot.downloadFile(it.content.media, outFile)
reply(it, "Saved to ${outFile.absolutePath}")
val file = File(directoryOrFile, pathedFile.filePath.filenameFromUrl).apply {
createNewFile()
writeBytes(bot.downloadFile(pathedFile))
}
reply(it, "Saved to ${file.absolutePath}")
}
onContentMessage { println(it) }
}.second.join()

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {

View File

@@ -2,9 +2,7 @@ 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.chat.CommonBot
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.chat.ExtendedBot
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.message.*
import kotlinx.coroutines.*
@@ -26,13 +24,7 @@ suspend fun main(vararg args: String) {
is UserForwardInfo -> {
val user = forwardInfo.from
when (user) {
is CommonUser -> {
if (user.isPremium) {
regular("Premium user ")
} else {
regular("User ")
}
}
is CommonUser -> regular("User ")
is CommonBot,
is ExtendedBot -> regular("Bot ")
} + code(user.id.chatId.toString()) + " (${user.firstName} ${user.lastName}: ${user.username ?.username ?: "Without username"})"
@@ -42,6 +34,8 @@ 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,6 +1,6 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {

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

@@ -1,6 +1,6 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {

View File

@@ -1,23 +1,20 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.sendTextMessage
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.linkMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2
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.types.ParseMode.MarkdownV2
import dev.inmo.tgbotapi.types.User
import dev.inmo.tgbotapi.types.chat.abstracts.*
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()
@@ -26,12 +23,12 @@ suspend fun main(vararg args: String) {
val chat = message.chat
if (chat is ChannelChat) {
val answer = "Hi everybody in this channel \"${chat.title}\""
send(chat, answer, MarkdownV2)
sendTextMessage(chat, answer, MarkdownV2)
return@onContentMessage
}
val answerText = "Oh, hi, " + when (chat) {
is User -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
is PrivateChat -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
is User -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
is SupergroupChat -> (chat.username ?.username ?: getChat(chat).inviteLink) ?.let {
chat.title.linkMarkdownV2(it)
} ?: chat.title

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
@@ -9,7 +9,7 @@ buildscript {
}
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
}

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.edit
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.formatting.botCommand
import dev.inmo.tgbotapi.extensions.utils.formatting.buildEntities
import dev.inmo.tgbotapi.extensions.utils.shortcuts.*
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,14 +86,12 @@ suspend fun activateKeyboardsBot(
return@onMessageDataCallbackQuery
}
val text = "This is $page of $count"
edit(
editMessageText(
it.message.withContent<TextContent>() ?: it.let {
answer(it, "Unsupported message type :(")
return@onMessageDataCallbackQuery
},
text,
"This is $page of $count",
replyMarkup = inlineKeyboard {
row {
includePageButtons(page, count)
@@ -102,22 +100,6 @@ 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,6 +1,6 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {

View File

@@ -1,19 +1,23 @@
import dev.inmo.micro_utils.common.filesize
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
import dev.inmo.tgbotapi.extensions.api.send.*
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.chat.Chat
import dev.inmo.tgbotapi.types.files.DocumentFile
import dev.inmo.tgbotapi.types.media.TelegramMediaDocument
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.mediaCountInMediaGroup
import kotlinx.coroutines.*
import java.io.File
private const val command = "send_file"
@@ -46,7 +50,7 @@ suspend fun main(args: Array<String>) {
)
else -> sendDocumentsGroup(
chat,
files.map { TelegramMediaDocument(it.asMultipartFile()) },
files.map { InputMediaDocument(it.asMultipartFile()) },
protectContent = true
)
}
@@ -65,9 +69,9 @@ suspend fun main(args: Array<String>) {
val chosen = mutableListOf<File>()
while (left > 0) {
val picked = pickFile() ?.takeIf { it.filesize > 0 } ?: continue
chosen.add(picked)
left--
val picked = pickFile() ?: continue
chosen.add(picked)
if (chosen.size >= mediaCountInMediaGroup.last) {
sendFiles(message.chat, chosen)
chosen.clear()
@@ -81,7 +85,7 @@ suspend fun main(args: Array<String>) {
}
if (!sent) {
reply(message, "Nothing selected :(")
bot.reply(message, "Nothing selected :(")
}
}
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
@@ -9,7 +9,7 @@ buildscript {
}
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
}

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,6 +8,7 @@ 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(
@@ -31,19 +32,19 @@ suspend fun activateResenderBot(
onVisualGallery {
val chat = it.chat ?: return@onVisualGallery
withUploadPhotoAction(chat) {
send(chat, it.map { it.content.toMediaGroupMemberTelegramMedia() })
sendVisualMediaGroup(chat, it.map { it.content.toMediaGroupMemberInputMedia() })
}
}
onPlaylist {
val chat = it.chat ?: return@onPlaylist
withUploadDocumentAction(chat) {
send(chat, it.map { it.content.toMediaGroupMemberTelegramMedia() })
sendPlaylist(chat, it.map { it.content.toMediaGroupMemberInputMedia() })
}
}
onDocumentsGroup {
val chat = it.chat ?: return@onDocumentsGroup
withUploadDocumentAction(chat) {
send(chat, it.map { it.content.toMediaGroupMemberTelegramMedia() })
sendDocumentsGroup(chat, it.map { it.content.toMediaGroupMemberInputMedia() })
}
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {

View File

@@ -1,26 +1,35 @@
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.micro_utils.coroutines.safely
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())
bot.buildBehaviourWithLongPolling(scope = CoroutineScope(Dispatchers.IO)) {
onDice {
val scope = CoroutineScope(Dispatchers.Default)
bot.longPolling(scope = scope) {
filterContentMessages<DiceContent>(scope).onEach {
val content = it.content
val dice = content.dice
val diceType = dice.animationType
if (diceType == SlotMachineDiceAnimationType) {
val result = dice.calculateSlotMachineResult() ?: return@onDice
reply(it, "${result.leftReel}|${result.centerReel}|${result.rightReel}")
} else {
reply(it, "There is no slot machine dice in message")
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")
}
}
}
}.join()
}
}.launchIn(scope)
}
scope.coroutineContext[Job]!!.join()
}

View File

@@ -1,17 +0,0 @@
# WebApp
Here you may find simple example of `WebApp`. For work of this example you will need one of two things:
* Your own domain with SSL (letsencrypt is okay)
* Test account in telegram
What is there in this module:
* JVM part of this example is a server with simple static webapp sharing and bot which just gives the webapp button to open webapp
* JS part is the WebApp with one button and reacting to chaged user theme and app viewport
## How to run
```kotlin
./gradlew run --args="TOKEN WEB_APP_ADDRESS"
```

View File

@@ -1,57 +0,0 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply plugin: 'application'
kotlin {
jvm()
js(IR) {
browser()
binaries.executable()
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version"
}
}
jsMain {
dependencies {
implementation "dev.inmo:tgbotapi.webapps:$telegram_bot_api_version"
}
}
jvmMain {
dependencies {
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
implementation "dev.inmo:micro_utils.ktor.server:$micro_utils_version"
implementation "io.ktor:ktor-server-cio:$ktor_version"
}
}
}
}
application {
mainClassName = "WebAppServerKt"
}
tasks.getByName("compileKotlinJvm")
.dependsOn(jsBrowserDistribution)
tasks.getByName("compileKotlinJvm").configure {
mustRunAfter jsBrowserDistribution
}

View File

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

View File

@@ -1,106 +0,0 @@
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
import dev.inmo.tgbotapi.types.webAppQueryIdField
import dev.inmo.tgbotapi.webapps.*
import dev.inmo.tgbotapi.webapps.haptic.HapticFeedbackStyle
import dev.inmo.tgbotapi.webapps.haptic.HapticFeedbackType
import io.ktor.client.HttpClient
import io.ktor.client.request.*
import io.ktor.client.statement.bodyAsText
import io.ktor.http.*
import io.ktor.http.content.TextContent
import kotlinx.browser.document
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) {
appendText(text)
appendElement("p", {})
}
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 ?.log(
if (dataIsSafe) {
"Data is safe"
} else {
"Data is unsafe"
}
)
document.body ?.log(
webApp.initDataUnsafe.chat.toString()
)
}
document.body ?.appendElement("button") {
addEventListener("click", {
scope.launchSafelyWithoutExceptions {
handleResult({ "Clicked" }) {
client.post("${window.location.origin.removeSuffix("/")}/inline") {
parameter(webAppQueryIdField, it)
setBody(TextContent("Clicked", ContentType.Text.Plain))
document.body ?.log(url.build().toString())
}.coroutineContext.job.join()
}
}
})
appendText("Example button")
} ?: window.alert("Unable to load body")
webApp.apply {
onThemeChanged {
document.body ?.log("Theme changed: ${webApp.themeParams}")
}
onViewportChanged {
document.body ?.log("Viewport changed: ${it.isStateStable}")
}
backButton.apply {
onClick {
document.body ?.log("Back button clicked")
hapticFeedback.impactOccurred(
HapticFeedbackStyle.Heavy
)
}
show()
}
mainButton.apply {
setText("Main button")
onClick {
document.body ?.log("Main button clicked")
hapticFeedback.notificationOccurred(
HapticFeedbackType.Success
)
}
show()
}
onSettingsButtonClicked {
document.body ?.log("Settings button clicked")
}
}
webApp.ready()
}.onFailure {
window.alert(it.stackTraceToString())
}
}
}

View File

@@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="format-detection" content="telephone=no"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="HandheldFriendly" content="True"/>
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<title>Web App Example</title>
</head>
<body>
<script type="application/javascript" src="https://telegram.org/js/telegram-web-app.js"></script>
<script type="application/javascript" src="WebApp.js"></script>
</body>
</html>

View File

@@ -1,123 +0,0 @@
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
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
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 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:
*
* * Telegram Token
* * URL where will be placed
*
* 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 telegramBotAPIUrlsKeeper = TelegramAPIUrlsKeeper(
args.first(),
testServer = args.any { it == "testServer" }
)
val bot = telegramBot(telegramBotAPIUrlsKeeper)
createKtorServer(
"0.0.0.0",
8080,
additionalEngineEnvironmentConfigurator = {
parentCoroutineContext += Dispatchers.IO
}
) {
routing {
static {
files(File("WebApp/build/distributions"))
default("WebApp/build/distributions/index.html")
}
post("inline") {
val requestBody = call.receiveText()
val queryId = call.parameters[webAppQueryIdField] ?: error("$webAppQueryIdField should be presented")
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.checkWebAppData(webAppCheckData.data, webAppCheckData.hash)
call.respond(HttpStatusCode.OK, isSafe.toString())
}
}
}.start(false)
bot.buildBehaviourWithLongPolling(
defaultExceptionsHandler = { it.printStackTrace() }
) {
onCommand("reply_markup") {
reply(
it,
"Button",
replyMarkup = replyKeyboard(resizeKeyboard = true, oneTimeKeyboard = true) {
row {
webAppButton("Open WebApp", WebAppInfo(args[1]))
}
}
)
}
onCommand("inline") {
reply(
it,
"Button",
replyMarkup = inlineKeyboard {
row {
webAppButton("Open WebApp", WebAppInfo(args[1]))
}
}
)
}
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"),
)
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
println(it)
}
println(getMe())
}.join()
}

View File

@@ -1,18 +1,7 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
}
}
allprojects {
repositories {
mavenLocal()
mavenCentral()
jcenter()
if (project.hasProperty("GITHUB_USER") && project.hasProperty("GITHUB_TOKEN")) {
maven {
url "https://maven.pkg.github.com/InsanusMokrassar/TelegramBotAPI"
@@ -23,4 +12,4 @@ allprojects {
}
}
}
}
}

View File

@@ -1,11 +1,7 @@
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.21
telegram_bot_api_version=2.1.1
micro_utils_version=0.11.6
serialization_version=1.3.3
ktor_version=2.0.2
telegram_bot_api_version=0.38.15
micro_utils_version=0.9.20

View File

@@ -16,6 +16,4 @@ include ":KeyboardsBot:jvm_launcher"
include ":SlotMachineDetectorBot"
include ":WebApp"
include ":FSMBot"