1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2026-08-20 08:06:21 +00:00

Require ephemeral receiver/message id and add EphemeralChatId variants

Ephemeral edit/delete/replyToEphemeral requests no longer derive receiverUserId
and ephemeralMessageId from a throwing default: both are plain required
parameters again. Each chatId-taking form instead gained a convenience variant
accepting an EphemeralChatId, which sources both values from the identifier and
delegates to the required-parameter form, so a missing ephemeralMessageId fails
in the thin overload rather than during serialization.

Adds EphemeralChatIdRequestsTest covering the delegation of the core variants.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-20 19:24:56 +06:00
parent a1d2ebb4dc
commit d48e951232
15 changed files with 768 additions and 90 deletions

View File

@@ -14,12 +14,20 @@ data class DeleteEphemeralMessage(
@OptIn(ExperimentalSerializationApi::class)
@SerialName(receiverUserIdField)
@EncodeDefault
override val receiverUserId: UserId = requireNotNull(chatId.receiverUser) { "receiverUserId was not provided and chatId ($chatId) is not an EphemeralChatId" },
override val receiverUserId: UserId,
@OptIn(ExperimentalSerializationApi::class)
@SerialName(ephemeralMessageIdField)
@EncodeDefault
override val ephemeralMessageId: EphemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "ephemeralMessageId was not provided and chatId ($chatId) does not carry an ephemeralMessageId" }
override val ephemeralMessageId: EphemeralMessageId
) : SimpleRequest<Unit>, EphemeralMessageAction {
constructor(
chatId: EphemeralChatId
): this(
chatId,
chatId.receiverUser,
requireNotNull(chatId.ephemeralMessageId) { "chatId ($chatId) does not carry an ephemeralMessageId" }
)
override fun method(): String = "deleteEphemeralMessage"
override val resultDeserializer: DeserializationStrategy<Unit>

View File

@@ -16,8 +16,8 @@ const val editEphemeralMessageCaptionMethod = "editEphemeralMessageCaption"
fun EditEphemeralMessageCaption(
chatId: ChatIdentifier,
receiverUserId: UserId = requireNotNull(chatId.receiverUser) { "receiverUserId was not provided and chatId ($chatId) is not an EphemeralChatId" },
ephemeralMessageId: EphemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "ephemeralMessageId was not provided and chatId ($chatId) does not carry an ephemeralMessageId" },
receiverUserId: UserId,
ephemeralMessageId: EphemeralMessageId,
caption: String? = null,
parseMode: ParseMode? = null,
replyMarkup: InlineKeyboardMarkup? = null
@@ -31,10 +31,24 @@ fun EditEphemeralMessageCaption(
replyMarkup = replyMarkup
)
fun EditEphemeralMessageCaption(
chatId: EphemeralChatId,
caption: String? = null,
parseMode: ParseMode? = null,
replyMarkup: InlineKeyboardMarkup? = null
) = EditEphemeralMessageCaption(
chatId = chatId,
receiverUserId = chatId.receiverUser,
ephemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "chatId ($chatId) does not carry an ephemeralMessageId" },
caption = caption,
parseMode = parseMode,
replyMarkup = replyMarkup
)
fun EditEphemeralMessageCaption(
chatId: ChatIdentifier,
receiverUserId: UserId = requireNotNull(chatId.receiverUser) { "receiverUserId was not provided and chatId ($chatId) is not an EphemeralChatId" },
ephemeralMessageId: EphemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "ephemeralMessageId was not provided and chatId ($chatId) does not carry an ephemeralMessageId" },
receiverUserId: UserId,
ephemeralMessageId: EphemeralMessageId,
entities: TextSourcesList,
replyMarkup: InlineKeyboardMarkup? = null
) = EditEphemeralMessageCaption(
@@ -47,6 +61,18 @@ fun EditEphemeralMessageCaption(
replyMarkup = replyMarkup
)
fun EditEphemeralMessageCaption(
chatId: EphemeralChatId,
entities: TextSourcesList,
replyMarkup: InlineKeyboardMarkup? = null
) = EditEphemeralMessageCaption(
chatId = chatId,
receiverUserId = chatId.receiverUser,
ephemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "chatId ($chatId) does not carry an ephemeralMessageId" },
entities = entities,
replyMarkup = replyMarkup
)
@ConsistentCopyVisibility
@Serializable
data class EditEphemeralMessageCaption internal constructor(
@@ -55,11 +81,11 @@ data class EditEphemeralMessageCaption internal constructor(
@OptIn(ExperimentalSerializationApi::class)
@SerialName(receiverUserIdField)
@EncodeDefault
override val receiverUserId: UserId = requireNotNull(chatId.receiverUser) { "receiverUserId was not provided and chatId ($chatId) is not an EphemeralChatId" },
override val receiverUserId: UserId,
@OptIn(ExperimentalSerializationApi::class)
@SerialName(ephemeralMessageIdField)
@EncodeDefault
override val ephemeralMessageId: EphemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "ephemeralMessageId was not provided and chatId ($chatId) does not carry an ephemeralMessageId" },
override val ephemeralMessageId: EphemeralMessageId,
@SerialName(captionField)
override val text: String? = null,
@SerialName(parseModeField)

View File

@@ -16,17 +16,28 @@ data class EditEphemeralMessageMedia(
@OptIn(ExperimentalSerializationApi::class)
@SerialName(receiverUserIdField)
@EncodeDefault
override val receiverUserId: UserId = requireNotNull(chatId.receiverUser) { "receiverUserId was not provided and chatId ($chatId) is not an EphemeralChatId" },
override val receiverUserId: UserId,
@OptIn(ExperimentalSerializationApi::class)
@SerialName(ephemeralMessageIdField)
@EncodeDefault
override val ephemeralMessageId: EphemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "ephemeralMessageId was not provided and chatId ($chatId) does not carry an ephemeralMessageId" },
override val ephemeralMessageId: EphemeralMessageId,
@Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
@SerialName(mediaField)
override val media: TelegramFreeMedia,
@SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null
) : EditEphemeralMessage, EditReplyMessage, EditMediaMessage {
constructor(
chatId: EphemeralChatId,
media: TelegramFreeMedia,
replyMarkup: InlineKeyboardMarkup? = null
): this(
chatId,
chatId.receiverUser,
requireNotNull(chatId.ephemeralMessageId) { "chatId ($chatId) does not carry an ephemeralMessageId" },
media,
replyMarkup
)
init {
require(media.file !is MultipartFile) {

View File

@@ -15,14 +15,23 @@ data class EditEphemeralMessageReplyMarkup(
@OptIn(ExperimentalSerializationApi::class)
@SerialName(receiverUserIdField)
@EncodeDefault
override val receiverUserId: UserId = requireNotNull(chatId.receiverUser) { "receiverUserId was not provided and chatId ($chatId) is not an EphemeralChatId" },
override val receiverUserId: UserId,
@OptIn(ExperimentalSerializationApi::class)
@SerialName(ephemeralMessageIdField)
@EncodeDefault
override val ephemeralMessageId: EphemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "ephemeralMessageId was not provided and chatId ($chatId) does not carry an ephemeralMessageId" },
override val ephemeralMessageId: EphemeralMessageId,
@SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null
) : EditEphemeralMessage, EditReplyMessage {
constructor(
chatId: EphemeralChatId,
replyMarkup: InlineKeyboardMarkup? = null
): this(
chatId,
chatId.receiverUser,
requireNotNull(chatId.ephemeralMessageId) { "chatId ($chatId) does not carry an ephemeralMessageId" },
replyMarkup
)
override fun method(): String = editEphemeralMessageReplyMarkupMethod
override val requestSerializer: SerializationStrategy<*>

View File

@@ -17,8 +17,8 @@ const val editEphemeralMessageTextMethod = "editEphemeralMessageText"
fun EditEphemeralMessageText(
chatId: ChatIdentifier,
receiverUserId: UserId = requireNotNull(chatId.receiverUser) { "receiverUserId was not provided and chatId ($chatId) is not an EphemeralChatId" },
ephemeralMessageId: EphemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "ephemeralMessageId was not provided and chatId ($chatId) does not carry an ephemeralMessageId" },
receiverUserId: UserId,
ephemeralMessageId: EphemeralMessageId,
text: String,
parseMode: ParseMode? = null,
linkPreviewOptions: LinkPreviewOptions? = null,
@@ -34,10 +34,26 @@ fun EditEphemeralMessageText(
replyMarkup = replyMarkup
)
fun EditEphemeralMessageText(
chatId: EphemeralChatId,
text: String,
parseMode: ParseMode? = null,
linkPreviewOptions: LinkPreviewOptions? = null,
replyMarkup: InlineKeyboardMarkup? = null
) = EditEphemeralMessageText(
chatId = chatId,
receiverUserId = chatId.receiverUser,
ephemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "chatId ($chatId) does not carry an ephemeralMessageId" },
text = text,
parseMode = parseMode,
linkPreviewOptions = linkPreviewOptions,
replyMarkup = replyMarkup
)
fun EditEphemeralMessageText(
chatId: ChatIdentifier,
receiverUserId: UserId = requireNotNull(chatId.receiverUser) { "receiverUserId was not provided and chatId ($chatId) is not an EphemeralChatId" },
ephemeralMessageId: EphemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "ephemeralMessageId was not provided and chatId ($chatId) does not carry an ephemeralMessageId" },
receiverUserId: UserId,
ephemeralMessageId: EphemeralMessageId,
entities: TextSourcesList,
linkPreviewOptions: LinkPreviewOptions? = null,
replyMarkup: InlineKeyboardMarkup? = null
@@ -52,6 +68,20 @@ fun EditEphemeralMessageText(
replyMarkup = replyMarkup
)
fun EditEphemeralMessageText(
chatId: EphemeralChatId,
entities: TextSourcesList,
linkPreviewOptions: LinkPreviewOptions? = null,
replyMarkup: InlineKeyboardMarkup? = null
) = EditEphemeralMessageText(
chatId = chatId,
receiverUserId = chatId.receiverUser,
ephemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "chatId ($chatId) does not carry an ephemeralMessageId" },
entities = entities,
linkPreviewOptions = linkPreviewOptions,
replyMarkup = replyMarkup
)
@ConsistentCopyVisibility
@Serializable
data class EditEphemeralMessageText internal constructor(
@@ -60,11 +90,11 @@ data class EditEphemeralMessageText internal constructor(
@OptIn(ExperimentalSerializationApi::class)
@SerialName(receiverUserIdField)
@EncodeDefault
override val receiverUserId: UserId = requireNotNull(chatId.receiverUser) { "receiverUserId was not provided and chatId ($chatId) is not an EphemeralChatId" },
override val receiverUserId: UserId,
@OptIn(ExperimentalSerializationApi::class)
@SerialName(ephemeralMessageIdField)
@EncodeDefault
override val ephemeralMessageId: EphemeralMessageId = requireNotNull(chatId.ephemeralMessageId) { "ephemeralMessageId was not provided and chatId ($chatId) does not carry an ephemeralMessageId" },
override val ephemeralMessageId: EphemeralMessageId,
@SerialName(textField)
override val text: String,
@SerialName(parseModeField)

View File

@@ -0,0 +1,107 @@
package dev.inmo.tgbotapi.types
import dev.inmo.tgbotapi.requests.DeleteEphemeralMessage
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.edit.caption.EditEphemeralMessageCaption
import dev.inmo.tgbotapi.requests.edit.media.EditEphemeralMessageMedia
import dev.inmo.tgbotapi.requests.edit.reply_markup.EditEphemeralMessageReplyMarkup
import dev.inmo.tgbotapi.requests.edit.text.EditEphemeralMessageText
import dev.inmo.tgbotapi.types.media.TelegramMediaPhoto
import kotlin.test.*
private val ephemeralChatIdRequestsChatId: RawChatId = RawChatId(111L)
private val ephemeralChatIdRequestsReceiverUser: UserId = ChatId(RawChatId(222L))
private val ephemeralChatIdRequestsMessageId = EphemeralMessageId(333L)
private val ephemeralChatIdWithMessageId = EphemeralChatId(
ephemeralChatIdRequestsChatId,
ephemeralChatIdRequestsReceiverUser,
ephemeralChatIdRequestsMessageId
)
private val ephemeralChatIdWithoutMessageId = EphemeralChatId(
ephemeralChatIdRequestsChatId,
ephemeralChatIdRequestsReceiverUser
)
private val ephemeralChatIdRequestsMedia = TelegramMediaPhoto(FileId("photo_file_id"))
class EphemeralChatIdRequestsTest {
@Test
fun `DeleteEphemeralMessage_built_from_EphemeralChatId_delegates_correctly`() {
val fromEphemeralChatId = DeleteEphemeralMessage(ephemeralChatIdWithMessageId)
val fromExplicitArgs = DeleteEphemeralMessage(
ephemeralChatIdWithMessageId,
ephemeralChatIdRequestsReceiverUser,
ephemeralChatIdRequestsMessageId
)
assertEquals(fromExplicitArgs, fromEphemeralChatId)
assertFailsWith<IllegalArgumentException> {
DeleteEphemeralMessage(ephemeralChatIdWithoutMessageId)
}
}
@Test
fun `EditEphemeralMessageMedia_built_from_EphemeralChatId_delegates_correctly`() {
val fromEphemeralChatId = EditEphemeralMessageMedia(
ephemeralChatIdWithMessageId,
ephemeralChatIdRequestsMedia
)
val fromExplicitArgs = EditEphemeralMessageMedia(
ephemeralChatIdWithMessageId,
ephemeralChatIdRequestsReceiverUser,
ephemeralChatIdRequestsMessageId,
ephemeralChatIdRequestsMedia
)
assertEquals(fromExplicitArgs, fromEphemeralChatId)
assertFailsWith<IllegalArgumentException> {
EditEphemeralMessageMedia(ephemeralChatIdWithoutMessageId, ephemeralChatIdRequestsMedia)
}
}
@Test
fun `EditEphemeralMessageReplyMarkup_built_from_EphemeralChatId_delegates_correctly`() {
val fromEphemeralChatId = EditEphemeralMessageReplyMarkup(ephemeralChatIdWithMessageId)
val fromExplicitArgs = EditEphemeralMessageReplyMarkup(
ephemeralChatIdWithMessageId,
ephemeralChatIdRequestsReceiverUser,
ephemeralChatIdRequestsMessageId
)
assertEquals(fromExplicitArgs, fromEphemeralChatId)
assertFailsWith<IllegalArgumentException> {
EditEphemeralMessageReplyMarkup(ephemeralChatIdWithoutMessageId)
}
}
@Test
fun `EditEphemeralMessageText_built_from_EphemeralChatId_delegates_correctly`() {
val fromEphemeralChatId = EditEphemeralMessageText(ephemeralChatIdWithMessageId, "text")
val fromExplicitArgs = EditEphemeralMessageText(
ephemeralChatIdWithMessageId,
ephemeralChatIdRequestsReceiverUser,
ephemeralChatIdRequestsMessageId,
"text"
)
assertEquals(fromExplicitArgs, fromEphemeralChatId)
assertFailsWith<IllegalArgumentException> {
EditEphemeralMessageText(ephemeralChatIdWithoutMessageId, "text")
}
}
@Test
fun `EditEphemeralMessageCaption_built_from_EphemeralChatId_delegates_correctly`() {
val fromEphemeralChatId = EditEphemeralMessageCaption(ephemeralChatIdWithMessageId, "caption")
val fromExplicitArgs = EditEphemeralMessageCaption(
ephemeralChatIdWithMessageId,
ephemeralChatIdRequestsReceiverUser,
ephemeralChatIdRequestsMessageId,
"caption"
)
assertEquals(fromExplicitArgs, fromEphemeralChatId)
assertFailsWith<IllegalArgumentException> {
EditEphemeralMessageCaption(ephemeralChatIdWithoutMessageId, "caption")
}
}
}