Skip to content

Commit 514d9d6

Browse files
add checks of save button and other fixes
1 parent 9746a06 commit 514d9d6

3 files changed

Lines changed: 109 additions & 9 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import dev.inmo.tgbotapi.types.buttons.PreparedKeyboardButtonId
2+
import dev.inmo.tgbotapi.types.request.RequestId
3+
import kotlin.random.Random
4+
import kotlin.random.nextUInt
5+
6+
val preparedSampleKeyboardRequestId = RequestId(Random.nextUInt().toUShort())

WebApp/src/jsMain/kotlin/main.kt

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import androidx.compose.runtime.*
22
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
33
import dev.inmo.tgbotapi.types.CustomEmojiId
4+
import dev.inmo.tgbotapi.types.buttons.PreparedKeyboardButtonId
45
import dev.inmo.tgbotapi.types.userIdField
56
import dev.inmo.tgbotapi.types.webAppQueryIdField
67
import dev.inmo.tgbotapi.webapps.*
@@ -17,6 +18,7 @@ import io.ktor.client.request.*
1718
import io.ktor.client.statement.bodyAsText
1819
import io.ktor.http.*
1920
import io.ktor.http.content.TextContent
21+
import kotlinx.browser.document
2022
import kotlinx.browser.window
2123
import kotlinx.coroutines.*
2224
import kotlinx.dom.appendElement
@@ -65,7 +67,12 @@ fun main() {
6567
}
6668
val scope = rememberCoroutineScope()
6769
val isSafeState = remember { mutableStateOf<Boolean?>(null) }
68-
val logsState = remember { mutableStateListOf<Any?>() }
70+
val logsState = remember {
71+
mutableStateListOf<Any?>(
72+
window.location.href,
73+
)
74+
}
75+
val buttonIdState = remember { mutableStateOf<PreparedKeyboardButtonId?>(null) }
6976

7077
// Text(window.location.href)
7178
// P()
@@ -94,6 +101,30 @@ fun main() {
94101
)
95102
}
96103

104+
LaunchedEffect(baseUrl) {
105+
val response = client.post("$baseUrl/getPreparedKeyboardButtonId") {
106+
setBody(
107+
Json.encodeToString(
108+
WebAppDataWrapper.serializer(),
109+
WebAppDataWrapper(webApp.initData, webApp.initDataUnsafe.hash)
110+
)
111+
)
112+
parameter(userIdField, webApp.initDataUnsafe.user ?.id ?.long ?: return@LaunchedEffect)
113+
}
114+
when (response.status) {
115+
HttpStatusCode.OK -> {
116+
val buttonId = response.bodyAsText()
117+
buttonIdState.value = PreparedKeyboardButtonId(buttonId)
118+
}
119+
HttpStatusCode.NoContent -> {
120+
buttonIdState.value = null
121+
}
122+
else -> {
123+
logsState.add("Error while getting prepared keyboard button id: ${response.status}")
124+
}
125+
}
126+
}
127+
97128
Text(
98129
when (isSafeState.value) {
99130
null -> "Checking safe state..."
@@ -249,6 +280,23 @@ fun main() {
249280
Text("Confirm")
250281
}
251282

283+
P()
284+
H3 { Text("Prepared keyboard button") }
285+
val buttonIdValue = buttonIdState.value
286+
if (buttonIdValue == null) {
287+
Text("Ensure that you have called /prepareKeyboard in bot. If you did it, check logs of server")
288+
} else {
289+
Button({
290+
onClick {
291+
webApp.requestChat(buttonIdValue) {
292+
logsState.add("Chat have been received: $it")
293+
}
294+
}
295+
}) {
296+
Text("Prepared keyboard button")
297+
}
298+
}
299+
252300
P()
253301
H3 { Text("Write access callbacks") }
254302
Button({
@@ -396,11 +444,15 @@ fun main() {
396444
}
397445
mainButton.apply {
398446
setText("Main button")
399-
setParams(
400-
BottomButtonParams(
401-
iconCustomEmojiId = CustomEmojiId("5370976574969486150") // 😏
447+
runCatching {
448+
setParams(
449+
BottomButtonParams(
450+
iconCustomEmojiId = CustomEmojiId("5370976574969486150") // 😏
451+
)
402452
)
403-
)
453+
}.onFailure {
454+
logsState.add("Can't set params for main button: $it")
455+
}
404456
onClick {
405457
logsState.add("Main button clicked")
406458
hapticFeedback.notificationOccurred(
@@ -411,11 +463,15 @@ fun main() {
411463
}
412464
secondaryButton.apply {
413465
setText("Secondary button")
414-
setParams(
415-
BottomButtonParams(
416-
iconCustomEmojiId = CustomEmojiId("5370763368497944736") // 😒
466+
runCatching {
467+
setParams(
468+
BottomButtonParams(
469+
iconCustomEmojiId = CustomEmojiId("5370763368497944736") // 😒
470+
)
417471
)
418-
)
472+
}.onFailure {
473+
logsState.add("Can't set params for secondary button: $it")
474+
}
419475
onClick {
420476
logsState.add("Secondary button clicked")
421477
hapticFeedback.notificationOccurred(

WebApp/src/jvmMain/kotlin/WebAppServer.kt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import dev.inmo.micro_utils.ktor.server.createKtorServer
55
import dev.inmo.tgbotapi.extensions.api.answers.answerInlineQuery
66
import dev.inmo.tgbotapi.extensions.api.bot.getMe
77
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
8+
import dev.inmo.tgbotapi.extensions.api.savePreparedKeyboardButton
89
import dev.inmo.tgbotapi.extensions.api.send.reply
910
import dev.inmo.tgbotapi.extensions.api.send.send
1011
import dev.inmo.tgbotapi.extensions.api.set.setUserEmojiStatus
@@ -21,6 +22,10 @@ import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton
2122
import dev.inmo.tgbotapi.types.*
2223
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle
2324
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent
25+
import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestManagedBot
26+
import dev.inmo.tgbotapi.types.buttons.PreparedKeyboardButton
27+
import dev.inmo.tgbotapi.types.buttons.PreparedKeyboardButtonId
28+
import dev.inmo.tgbotapi.types.buttons.reply.requestManagedBotReplyButton
2429
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
2530
import dev.inmo.tgbotapi.utils.*
2631
import io.ktor.http.*
@@ -59,6 +64,7 @@ suspend fun main(vararg args: String) {
5964
val initiationLogger = KSLog("Initialization")
6065

6166
val bot = telegramBot(telegramBotAPIUrlsKeeper)
67+
val usersToButtonsMap = mutableMapOf<UserId, PreparedKeyboardButtonId>()
6268
createKtorServer(
6369
"0.0.0.0",
6470
args.getOrNull(2) ?.toIntOrNull() ?: 8080
@@ -123,6 +129,24 @@ suspend fun main(vararg args: String) {
123129

124130
call.respond(HttpStatusCode.OK, set.toString())
125131
}
132+
post("getPreparedKeyboardButtonId") {
133+
val requestBody = call.receiveText()
134+
val webAppCheckData = Json.decodeFromString(WebAppDataWrapper.serializer(), requestBody)
135+
136+
val isSafe = telegramBotAPIUrlsKeeper.checkWebAppData(webAppCheckData.data, webAppCheckData.hash)
137+
val rawUserId = call.parameters[userIdField] ?.toLongOrNull() ?.let(::RawChatId) ?: error("$userIdField should be presented as long value")
138+
139+
if (isSafe) {
140+
val buttonId = usersToButtonsMap[UserId(rawUserId)]
141+
if (buttonId == null) {
142+
call.respond(HttpStatusCode.NoContent)
143+
} else {
144+
call.respond(HttpStatusCode.OK, buttonId.string)
145+
}
146+
} else {
147+
call.respond(HttpStatusCode.Forbidden)
148+
}
149+
}
126150
}
127151
}.start(false)
128152

@@ -171,6 +195,20 @@ suspend fun main(vararg args: String) {
171195
)
172196
)
173197
}
198+
onCommand("prepareKeyboard") {
199+
val preparedKeyboardButton = savePreparedKeyboardButton(
200+
userId = it.chat.id.toChatId(),
201+
button = requestManagedBotReplyButton(
202+
text = "Saved sample button",
203+
requestManagedBot = KeyboardButtonRequestManagedBot(
204+
requestId = preparedSampleKeyboardRequestId,
205+
suggestedName = "Saved sample button bot",
206+
suggestedUsername = Username.prepare("saved_sample_button_bot")
207+
)
208+
)
209+
)
210+
usersToButtonsMap[it.chat.id.toChatId()] = preparedKeyboardButton.id
211+
}
174212
onBaseInlineQuery {
175213
answerInlineQuery(
176214
it,

0 commit comments

Comments
 (0)