Compare commits

...

2 Commits

7 changed files with 174 additions and 113 deletions

View File

@ -5,7 +5,7 @@
</option> </option>
<option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" /> <option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" />
<module name="Coeur Morny Cono" /> <module name="Coeur Morny Cono" />
<option name="PROGRAM_PARAMETERS" value="--quiet --debug -t --username sukazyo_deving_bot --master 793274677 --trusted-chat -1 --auto-cmd --outdated-block --trusted-reader-dinner 1040613596 --report-to 793274677 -medc 793274677 -medt 0,2,18,19 -medtz 8 --dinner-chat -1001670950261" /> <option name="PROGRAM_PARAMETERS" value="--quiet --debug -t --username sukazyo_deving_bot --master 793274677 --trusted-chat -1 --auto-cmd --outdated-ignore --trusted-reader-dinner 1040613596 --report-to 793274677 -medc 793274677 -medt 0,2,18,19 -medtz 8 --dinner-chat -1001670950261" />
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" /> <option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" />
<extension name="coverage"> <extension name="coverage">
<pattern> <pattern>

View File

@ -5,7 +5,8 @@
</option> </option>
<option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" /> <option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" />
<module name="Coeur Morny Cono" /> <module name="Coeur Morny Cono" />
<option name="PROGRAM_PARAMETERS" value="--quiet --debug --username sukazyo_deving_bot --master 793274677 --trusted-chat -1 --outdated-block --trusted-reader-dinner 1040613596 -medc 793274677 -medt 0,2,18,19 -medtz 8 --dinner-chat -1001670950261" /> <option name="PROGRAM_PARAMETERS" value="--quiet --debug --username sukazyo_deving_bot --master 793274677 --trusted-chat -1 --outdated-ignore --trusted-reader-dinner 1040613596 -medc 793274677 -medtz 8 --dinner-chat -1001670950261" />
<option name="VM_PARAMETERS" value="-Djava.net.useSystemProxies=true" />
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" /> <option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" />
<extension name="coverage"> <extension name="coverage">
<pattern> <pattern>

View File

@ -5,7 +5,7 @@
</option> </option>
<option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" /> <option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" />
<module name="Coeur Morny Cono" /> <module name="Coeur Morny Cono" />
<option name="PROGRAM_PARAMETERS" value="--quiet --debug --username sukazyo_deving_bot --master 793274677 --trusted-chat -1 --auto-cmd --outdated-block --trusted-reader-dinner 1040613596 --report-to 793274677 -medc 793274677 -medt 0,2,18,19 -medtz 8 --dinner-chat -1001670950261" /> <option name="PROGRAM_PARAMETERS" value="--quiet --debug --username sukazyo_deving_bot --master 793274677 --trusted-chat -1 --auto-cmd --outdated-ignore --trusted-reader-dinner 1040613596 --report-to 793274677 -medc 793274677 -medt 0,2,18,19 -medtz 8 --dinner-chat -1001670950261" />
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" /> <option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" />
<extension name="coverage"> <extension name="coverage">
<pattern> <pattern>

View File

@ -187,19 +187,23 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
private var _httpServerContext: MornyHttpServerContext = MornyHttpServerContextImpl() private var _httpServerContext: MornyHttpServerContext = MornyHttpServerContextImpl()
// Coeur Initializing Pre Event // Coeur Initializing Pre Event
modules.foreach(it => it.onInitializingPre(OnInitializingPreContext( tryCallModulesEvent("onInitializingPre", _.onInitializingPre(OnInitializingPreContext(
externalContext, externalContext,
coeurStartTimestamp, account, username, userid, tasks, trusted, coeurStartTimestamp, account, username, userid, tasks, trusted,
eventManager, commands, queries, eventManager, commands, queries,
_httpServerContext, _httpServerContext,
initializeContext))) initializeContext)))
{
// register core/api events // register core/api events
eventManager register MornyOnUpdateTimestampOffsetLock() eventManager register MornyOnUpdateTimestampOffsetLock()
eventManager register MornyOnTelegramCommand(using commands) eventManager register MornyOnTelegramCommand(using commands)
eventManager register MornyOnInlineQuery(using queries) eventManager register MornyOnInlineQuery(using queries)
eventManager register _messageThreading.NextMessageCatcher eventManager register _messageThreading.NextMessageCatcher
{ // register core commands
// register core commands
import bot.command.* import bot.command.*
val $MornyHellos = MornyHellos() val $MornyHellos = MornyHellos()
val $MornyInformation = MornyInformation() val $MornyInformation = MornyInformation()
@ -223,13 +227,18 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
errorMessageManager.ShowErrorMessageCommand, errorMessageManager.ShowErrorMessageCommand,
) )
}
// register core utils events
eventManager register $MornyHellos.PrivateChat_O
// register core http api service // register core http api service
import cc.sukazyo.cono.morny.core.http.services as http_srv import cc.sukazyo.cono.morny.core.http.services as http_srv
_httpServerContext register4API http_srv.Ping() _httpServerContext register4API http_srv.Ping()
}
// Coeur Initializing Event // Coeur Initializing Event
modules.foreach(it => it.onInitializing(OnInitializingContext( tryCallModulesEvent("onInitializing", _.onInitializing(OnInitializingContext(
externalContext, externalContext,
coeurStartTimestamp, account, username, userid, tasks, trusted, coeurStartTimestamp, account, username, userid, tasks, trusted,
eventManager, commands, queries, eventManager, commands, queries,
@ -246,7 +255,7 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
initializeContext / this << watchDog initializeContext / this << watchDog
// Coeur Initializing Post Event // Coeur Initializing Post Event
modules.foreach(it => it.onInitializingPost(OnInitializingPostContext( tryCallModulesEvent("onInitializingPost", _.onInitializingPost(OnInitializingPostContext(
externalContext, externalContext,
coeurStartTimestamp, account, username, userid, tasks, trusted, coeurStartTimestamp, account, username, userid, tasks, trusted,
eventManager, commands, queries, eventManager, commands, queries,
@ -264,7 +273,7 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
configure_exitCleanup() configure_exitCleanup()
// Coeur Starting Event // Coeur Starting Event
modules.foreach(it => it.onStarting(OnStartingContext( tryCallModulesEvent("onStarting", _.onStarting(OnStartingContext(
initializeContext))) initializeContext)))
logger `info` "start http server" logger `info` "start http server"
@ -319,7 +328,7 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
}) })
// Coeur Starting Post Event // Coeur Starting Post Event
modules.foreach(it => it.onStartingPost(OnStartingPostContext( tryCallModulesEvent("onStartingPost", _.onStartingPost(OnStartingPostContext(
initializeContext))) initializeContext)))
if config.commandLoginRefresh then if config.commandLoginRefresh then
@ -372,7 +381,7 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
} }
def saveDataAll(): Unit = { def saveDataAll(): Unit = {
modules.foreach(it => it.onRoutineSavingData) tryCallModulesEvent("onRoutineSaveData", _.onRoutineSavingData)
logger `notice` "done all save action." logger `notice` "done all save action."
} }
@ -385,7 +394,7 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
private def exitCleanup (): Unit = { private def exitCleanup (): Unit = {
// Morny Exiting // Morny Exiting
modules.foreach(it => it.onExiting) tryCallModulesEvent("onExiting", _.onExiting)
account.removeGetUpdatesListener() account.removeGetUpdatesListener()
logger `info` "stopped bot update listener" logger `info` "stopped bot update listener"
@ -395,12 +404,12 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
// Morny Exiting Post // Morny Exiting Post
if config.commandLogoutClear then if config.commandLogoutClear then
commands.automaticTGListRemove() commands.automaticTGListRemove()
modules.foreach(it => it.onExitingPost) tryCallModulesEvent("onExitingPost", _.onExitingPost)
account.shutdown() account.shutdown()
logger `info` "stopped bot account" logger `info` "stopped bot account"
// Morny Exited // Morny Exited
modules.foreach(it => it.onExited) tryCallModulesEvent("onExited", _.onExited)
logger `info` "done exit cleanup\nMorny will EXIT now" logger `info` "done exit cleanup\nMorny will EXIT now"
} }
@ -415,6 +424,15 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
private case class LoginResult(account: TelegramBot, username: String, userid: Long) private case class LoginResult(account: TelegramBot, username: String, userid: Long)
private def tryCallModulesEvent (eventName: String, calls: MornyModule=>Unit): Unit =
modules.foreach { mod =>
try { calls(mod) }
catch case e: Exception =>
logger `error`
s"""Morny Coeur Lifecycle Event `$eventName` execution failed on module ${mod.id}
|${e.toLogString}""".stripMargin
}
private def login (skip_login: Boolean = false): Option[LoginResult] = { private def login (skip_login: Boolean = false): Option[LoginResult] = {
val builder = TelegramBot.Builder(config.telegramBotKey) val builder = TelegramBot.Builder(config.telegramBotKey)

View File

@ -1,12 +1,14 @@
package cc.sukazyo.cono.morny.core.bot.command package cc.sukazyo.cono.morny.core.bot.command
import cc.sukazyo.cono.morny.core.MornyCoeur import cc.sukazyo.cono.morny.core.MornyCoeur
import cc.sukazyo.cono.morny.core.bot.api.{ICommandAlias, ITelegramCommand} import cc.sukazyo.cono.morny.core.bot.api.{EventEnv, EventListener, ICommandAlias, ITelegramCommand}
import cc.sukazyo.cono.morny.core.bot.api.ICommandAlias.ListedAlias import cc.sukazyo.cono.morny.core.bot.api.ICommandAlias.ListedAlias
import cc.sukazyo.cono.morny.core.bot.api.messages.MessagingContext
import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.data.TelegramStickers
import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.InputCommand
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Chat.notOfType
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Requests.unsafeExecute import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Requests.unsafeExecute
import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.{Chat, Update}
import com.pengrad.telegrambot.request.SendSticker import com.pengrad.telegrambot.request.SendSticker
import com.pengrad.telegrambot.TelegramBot import com.pengrad.telegrambot.TelegramBot
@ -23,10 +25,13 @@ class MornyHellos (using coeur: MornyCoeur) {
override val description: String = "检查是否在线" override val description: String = "检查是否在线"
override def execute (using command: InputCommand, event: Update): Unit = override def execute (using command: InputCommand, event: Update): Unit =
this.sendSticker(using MessagingContext.extract(using event.message))
def sendSticker (using cxt: MessagingContext.WithMessage): Unit =
SendSticker( SendSticker(
event.message.chat.id, cxt.bind_chat.id,
TelegramStickers ID_ONLINE_STATUS_RETURN TelegramStickers ID_ONLINE_STATUS_RETURN
).replyToMessageId(event.message.messageId) ).replyToMessageId(cxt.bind_message.messageId)
.unsafeExecute .unsafeExecute
} }
@ -47,4 +52,18 @@ class MornyHellos (using coeur: MornyCoeur) {
} }
object PrivateChat_O extends EventListener {
override def onMessage (using event: EventEnv): Unit = {
import event.update
if update.message.chat notOfType Chat.Type.Private then
return;
if update.message.text == "o" || update.message.text == "O" then
On.sendSticker(using MessagingContext.extract(using update.message))
}
}
} }

View File

@ -32,6 +32,7 @@ class MedicationTimer (using coeur: MornyCoeur) {
private var lastNotify_messageId: Option[Int] = None private var lastNotify_messageId: Option[Int] = None
private var isScheduleTaskRegistered = false
private val scheduleTask: RoutineTask = new RoutineTask { private val scheduleTask: RoutineTask = new RoutineTask {
override def name: String = DAEMON_THREAD_NAME_DEF override def name: String = DAEMON_THREAD_NAME_DEF
@ -59,11 +60,15 @@ class MedicationTimer (using coeur: MornyCoeur) {
logger `notice` "Medication Timer disabled : related param is not complete set" logger `notice` "Medication Timer disabled : related param is not complete set"
return; return;
coeur.tasks ++ scheduleTask coeur.tasks ++ scheduleTask
isScheduleTaskRegistered = true
logger `notice` "Medication Timer started." logger `notice` "Medication Timer started."
def stop(): Unit = def stop(): Unit =
if isScheduleTaskRegistered then
coeur.tasks % scheduleTask coeur.tasks % scheduleTask
logger `notice` "Medication Timer stopped." logger `notice` "Medication Timer stopped."
else
logger `notice` "Medication Timer have not run, skipped stop it."
private def sendNotification(): Unit = { private def sendNotification(): Unit = {
val sendResponse: SendResponse = SendMessage(notify_toChat, NOTIFY_MESSAGE).unsafeExecute val sendResponse: SendResponse = SendMessage(notify_toChat, NOTIFY_MESSAGE).unsafeExecute
@ -82,7 +87,7 @@ class MedicationTimer (using coeur: MornyCoeur) {
notify_toChat, notify_toChat,
edited.messageId, edited.messageId,
edited.text + s"\n-- $editTime --" edited.text + s"\n-- $editTime --"
).entities((entities toArray)*).unsafeExecute ).entities(entities.toArray*).unsafeExecute
lastNotify_messageId = None lastNotify_messageId = None
true true
} }

View File

@ -3,7 +3,7 @@ package cc.sukazyo.cono.morny.util.tgapi
import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException
import cc.sukazyo.cono.morny.util.EpochDateTime.EpochSeconds import cc.sukazyo.cono.morny.util.EpochDateTime.EpochSeconds
import com.pengrad.telegrambot.TelegramBot import com.pengrad.telegrambot.TelegramBot
import com.pengrad.telegrambot.model.* import com.pengrad.telegrambot.model.{Chat as TChat, ChatMember as TChatMember, File as TFile, Message as TMessage, MessageEntity as TMessageEntity, Update as TUpdate, User as TUser}
import com.pengrad.telegrambot.request.{BaseRequest, GetChatMember} import com.pengrad.telegrambot.request.{BaseRequest, GetChatMember}
import com.pengrad.telegrambot.response.BaseResponse import com.pengrad.telegrambot.response.BaseResponse
@ -54,43 +54,43 @@ object TelegramExtensions {
}} }}
object Update { extension (update: Update) { object Update { extension (update: TUpdate) {
/** Get the [[Chat]] that the update comes from. /** Get the [[TChat]] that the update comes from.
* *
* For the update types that is non-chat related, or the update types that framework does not * For the update types that is non-chat related, or the update types that framework does not
* supported yet, this method will return [[None]]. * supported yet, this method will return [[None]].
* *
* ### Supported Update Types * ### Supported Update Types
* *
* Belows are the supported update types that will return a valid [[Chat]]. * Belows are the supported update types that will return a valid [[TChat]].
* *
* - [[Update.message]]: Chat that the message belongs. * - [[TUpdate.message]]: Chat that the message belongs.
* - [[Update.editedMessage]]: Chat that the edited message belongs. * - [[TUpdate.editedMessage]]: Chat that the edited message belongs.
* - [[Update.channelPost]]: Chat that the channel post message belongs. * - [[TUpdate.channelPost]]: Chat that the channel post message belongs.
* - [[Update.editedChannelPost]]: Chat that the edited channel post message belongs. * - [[TUpdate.editedChannelPost]]: Chat that the edited channel post message belongs.
* - [[Update.callbackQuery]]: Chat that the callback query's source message (a callback query * - [[TUpdate.callbackQuery]]: Chat that the callback query's source message (a callback query
* is triggered from a inline message button, that inline message is the source message) belongs. * is triggered from a inline message button, that inline message is the source message) belongs.
* - [[Update.myChatMember]]: Chat that where member status of current bot changed there. * - [[TUpdate.myChatMember]]: Chat that where member status of current bot changed there.
* - [[Update.chatMember]]: Chat that any one user's member status changed there. * - [[TUpdate.chatMember]]: Chat that any one user's member status changed there.
* - [[Update.chatJoinRequest]]: Chat that the join request comes from. * - [[TUpdate.chatJoinRequest]]: Chat that the join request comes from.
* *
* Belows are the known update types that is not chat related, so there's only a [[None]] returned. * Belows are the known update types that is not chat related, so there's only a [[None]] returned.
* *
* - [[Update.inlineQuery]] * - [[TUpdate.inlineQuery]]
* - [[Update.chosenInlineResult]] * - [[TUpdate.chosenInlineResult]]
* - [[Update.shippingQuery]] * - [[TUpdate.shippingQuery]]
* - [[Update.preCheckoutQuery]] * - [[TUpdate.preCheckoutQuery]]
* - [[Update.poll]] * - [[TUpdate.poll]]
* - [[Update.pollAnswer]] * - [[TUpdate.pollAnswer]]
* *
* Supported up to Telegram Bot API 6.2 * Supported up to Telegram Bot API 6.2
* *
* @return An [[Option]] either contains a [[Chat]] that the update comes from, or [[None]] if there's * @return An [[Option]] either contains a [[TChat]] that the update comes from, or [[None]] if there's
* no user or update type is unsupported. * no user or update type is unsupported.
* @since 2.0.0 * @since 2.0.0
*/ */
def sourceChat: Option[Chat] = def sourceChat: Option[TChat] =
if (update.message != null) Some(update.message.chat) if (update.message != null) Some(update.message.chat)
else if (update.editedMessage != null) Some(update.editedMessage.chat) else if (update.editedMessage != null) Some(update.editedMessage.chat)
else if (update.channelPost != null) Some(update.channelPost.chat) else if (update.channelPost != null) Some(update.channelPost.chat)
@ -107,42 +107,42 @@ object TelegramExtensions {
else if (update.chatJoinRequest != null) Some(update.chatJoinRequest.chat) else if (update.chatJoinRequest != null) Some(update.chatJoinRequest.chat)
else None else None
/** Get the [[User]] that the update comes from. /** Get the [[TUser]] that the update comes from.
* *
* For the update types that is non-user related, or the update types that framework does not * For the update types that is non-user related, or the update types that framework does not
* supported yet, this method will return [[None]]. * supported yet, this method will return [[None]].
* *
* ### Supported Update Types * ### Supported Update TypesT
* *
* Belows are the supported update types that will return a valid [[User]]. * Belows are the supported update types that will return a valid [[TUser]].
* *
* - [[Update.message]]: User that sent the message. * - [[TUpdate.message]]: User that sent the message.
* - [[Update.editedMessage]]: User that sent the message. Notice that is the user who ORIGINAL * - [[TUpdate.editedMessage]]: User that sent the message. Notice that is the user who ORIGINAL
* SENT the message but NOT EDITED the message due to the API limitation, while in current Bot * SENT the message but NOT EDITED the message due to the API limitation, while in current Bot
* API version (v7.0), editing other's message is not allowed so it should have no problem. * API version (v7.0), editing other's message is not allowed so it should have no problem.
* - [[Update.inlineQuery]]: User that executing the inline query. * - [[TUpdate.inlineQuery]]: User that executing the inline query.
* - [[Update.chosenInlineResult]]: User that chosen the inline result of a inline query. * - [[TUpdate.chosenInlineResult]]: User that chosen the inline result of a inline query.
* - [[Update.callbackQuery]]: User that triggered the callback query. * - [[TUpdate.callbackQuery]]: User that triggered the callback query.
* - [[Update.shippingQuery]]: User that sent the shipping query. * - [[TUpdate.shippingQuery]]: User that sent the shipping query.
* - [[Update.preCheckoutQuery]]: User that sent the pre-checkout query. * - [[TUpdate.preCheckoutQuery]]: User that sent the pre-checkout query.
* - [[Update.pollAnswer]]: User that answered a un-anonymous poll. * - [[TUpdate.pollAnswer]]: User that answered a un-anonymous poll.
* - [[Update.myChatMember]]: Current bot that my member status changed. * - [[TUpdate.myChatMember]]: Current bot that my member status changed.
* - [[Update.chatMember]]: User that their member status changed. * - [[TUpdate.chatMember]]: User that their member status changed.
* - [[Update.chatJoinRequest]]: User that sent a join request. * - [[TUpdate.chatJoinRequest]]: User that sent a join request.
* *
* Belows are the known update types that is not user related, so there's only a [[None]] returned. * Belows are the known update types that is not user related, so there's only a [[None]] returned.
* *
* - [[Update.channelPost]] * - [[TUpdate.channelPost]]
* - [[Update.editedChannelPost]] * - [[TUpdate.editedChannelPost]]
* - [[Update.poll]] <small>(odd, but it is no sender in the latest Bot API 7.0)</small> * - [[TUpdate.poll]] <small>(odd, but it is no sender in the latest Bot API 7.0)</small>
* *
* Supported up to Telegram Bot API 6.2 * Supported up to Telegram Bot API 6.2
* *
* @return An [[Option]] either contains a [[User]] that the update comes from, or [[None]] if there's * @return An [[Option]] either contains a [[TUser]] that the update comes from, or [[None]] if there's
* no user or update type is unsupported. * no user or update type is unsupported.
* @since 2.0.0 * @since 2.0.0
*/ */
def sourceUser: Option[User] = def sourceUser: Option[TUser] =
if (update.message != null) Some(update.message.from) if (update.message != null) Some(update.message.from)
else if (update.editedMessage != null) Some(update.editedMessage.from) else if (update.editedMessage != null) Some(update.editedMessage.from)
else if (update.channelPost != null) None else if (update.channelPost != null) None
@ -173,25 +173,25 @@ object TelegramExtensions {
* *
* Belows are the supported update types that will return a valid time. * Belows are the supported update types that will return a valid time.
* *
* - [[Update.message]]: Time that the message is sent. Should be fixed and accurate. * - [[TUpdate.message]]: Time that the message is sent. Should be fixed and accurate.
* - [[Update.editedMessage]]: Time that the message is edited. Can be changed when the message is * - [[TUpdate.editedMessage]]: Time that the message is edited. Can be changed when the message is
* edited again, but should be the fixed editing time in the specific update. * edited again, but should be the fixed editing time in the specific update.
* - [[Update.channelPost]]: Time that the channel post message is sent. Should be fixed and accurate. * - [[TUpdate.channelPost]]: Time that the channel post message is sent. Should be fixed and accurate.
* - [[Update.editedChannelPost]]: Time that the channel post message is edited. Same with * - [[TUpdate.editedChannelPost]]: Time that the channel post message is edited. Same with
* [[Update.editedMessage]] * [[TUpdate.editedMessage]]
* - [[Update.myChatMember]]: Time that the member status of current bot changes done. * - [[TUpdate.myChatMember]]: Time that the member status of current bot changes done.
* - [[Update.chatMember]]: Time that one user's member status changes done. * - [[TUpdate.chatMember]]: Time that one user's member status changes done.
* - [[Update.chatJoinRequest]]: Time that the join request is sent. * - [[TUpdate.chatJoinRequest]]: Time that the join request is sent.
* *
* Belows have no any time information, so there's only a [[None]] returned. * Belows have no any time information, so there's only a [[None]] returned.
* *
* - [[Update.inlineQuery]] * - [[TUpdate.inlineQuery]]
* - [[Update.chosenInlineResult]] * - [[TUpdate.chosenInlineResult]]
* - [[Update.callbackQuery]] * - [[TUpdate.callbackQuery]]
* - [[Update.shippingQuery]] * - [[TUpdate.shippingQuery]]
* - [[Update.preCheckoutQuery]] * - [[TUpdate.preCheckoutQuery]]
* - [[Update.poll]] * - [[TUpdate.poll]]
* - [[Update.pollAnswer]] * - [[TUpdate.pollAnswer]]
* *
* Supported up to Telegram Bot API 6.2 * Supported up to Telegram Bot API 6.2
* *
@ -218,32 +218,32 @@ object TelegramExtensions {
}} }}
object Chat { extension (chat: Chat) { object Chat { extension (chat: TChat) {
/** Check if a user is a member of this chat. /** Check if a user is a member of this chat.
* *
* It is equivalent to `memberHasPermission(user, ChatMember.Status.member)`. * It is equivalent to `memberHasPermission(user, ChatMember.Status.member)`.
* *
* It checks if the user's member status is [[ChatMember.Status.member]], so if the member is in * It checks if the user's member status is [[TChatMember.Status.member]], so if the member is in
* this chat but they are been [[ChatMember.Status.restricted]], it will be treated as *not a member*. * this chat but they are been [[TChatMember.Status.restricted]], it will be treated as *not a member*.
* *
* It needs to execute a request getting chat member, so it requires a live [[TelegramBot]] instance, * It needs to execute a request getting chat member, so it requires a live [[TelegramBot]] instance,
* and the bot needs to be a member of this chat so that it can read the chat member. * and the bot needs to be a member of this chat so that it can read the chat member.
* *
* This method will only use the [[Chat]]'s [[Chat.id]], so it is safe to call on a [[LimboChat]]. * This method will only use the [[TChat]]'s [[TChat.id]], so it is safe to call on a [[LimboChat]].
* *
* **Notice:** This method will execute a request to the Telegram Bot API, so it may be slow. * **Notice:** This method will execute a request to the Telegram Bot API, so it may be slow.
* *
* @see [[memberHasPermission]] * @see [[memberHasPermission]]
* *
* @param user The user that want to check if they are a member of this chat.Only its [[User.id]] will * @param user The user that want to check if they are a member of this chat.Only its [[TUser.id]] will
* be used so it is safe using a [[LimboUser]]. * be used so it is safe using a [[LimboUser]].
* @return [[true]] when the user is a member of this chat, [[false]] otherwise. * @return [[true]] when the user is a member of this chat, [[false]] otherwise.
* *
* @since 1.0.0 * @since 1.0.0
*/ */
def hasMember (user: User) (using TelegramBot): Boolean = def hasMember (user: TUser) (using TelegramBot): Boolean =
memberHasPermission(user, ChatMember.Status.member) memberHasPermission(user, TChatMember.Status.member)
/** Check if a user has a permission level in this chat. /** Check if a user has a permission level in this chat.
* *
@ -261,20 +261,20 @@ object TelegramExtensions {
* | [[ChatMember.Status.left]] | -3 | * | [[ChatMember.Status.left]] | -3 |
* | [[ChatMember.Status.kicked]] | -5 | * | [[ChatMember.Status.kicked]] | -5 |
* *
* This method will only use the [[Chat]]'s [[Chat.id]], so it is safe to call on a [[LimboChat]]. * This method will only use the [[TChat]]'s [[TChat.id]], so it is safe to call on a [[LimboChat]].
* *
* **Notice:** This method will execute a request to the Telegram Bot API, so it may be slow. * **Notice:** This method will execute a request to the Telegram Bot API, so it may be slow.
* *
* @since 1.0.0 * @since 1.0.0
* *
* @param user The user that wanted to check if they have the permission. Only its [[User.id]] will * @param user The user that wanted to check if they have the permission. Only its [[TUser.id]] will
* be used so it is safe using a [[LimboUser]]. * be used so it is safe using a [[LimboUser]].
* @param permission The required permission level. * @param permission The required permission level.
* @param bot A live [[TelegramBot]] that will be used to execute the getChatMember request. It * @param bot A live [[TelegramBot]] that will be used to execute the getChatMember request. It
* should be a member of this chat so that can read the chat member for this method works. * should be a member of this chat so that can read the chat member for this method works.
* @return [[true]] if the user have the permission or higher permission, [[false]] otherwise. * @return [[true]] if the user have the permission or higher permission, [[false]] otherwise.
*/ */
def memberHasPermission (user: User, permission: ChatMember.Status) (using bot: TelegramBot): Boolean = { def memberHasPermission (user: TUser, permission: TChatMember.Status) (using bot: TelegramBot): Boolean = {
//noinspection ScalaUnusedSymbol //noinspection ScalaUnusedSymbol
enum UserPermissionLevel(val level: Int): enum UserPermissionLevel(val level: Int):
@ -287,28 +287,46 @@ object TelegramExtensions {
@targetName("equalOrGreaterThan") @targetName("equalOrGreaterThan")
def >= (another: UserPermissionLevel): Boolean = this.level >= another.level def >= (another: UserPermissionLevel): Boolean = this.level >= another.level
object UserPermissionLevel: object UserPermissionLevel:
def apply(status: ChatMember.Status): UserPermissionLevel = def apply(status: TChatMember.Status): UserPermissionLevel =
status match status match
case ChatMember.Status.creator => CREATOR case TChatMember.Status.creator => CREATOR
case ChatMember.Status.administrator => ADMINISTRATOR case TChatMember.Status.administrator => ADMINISTRATOR
case ChatMember.Status.member => MEMBER case TChatMember.Status.member => MEMBER
case ChatMember.Status.restricted => RESTRICTED case TChatMember.Status.restricted => RESTRICTED
case ChatMember.Status.left => LEFT case TChatMember.Status.left => LEFT
case ChatMember.Status.kicked => KICKED case TChatMember.Status.kicked => KICKED
def apply (chatMember: ChatMember): UserPermissionLevel = apply(chatMember.status) def apply (chatMember: TChatMember): UserPermissionLevel = apply(chatMember.status)
import Requests.execute import Requests.execute
val chatMember: ChatMember = GetChatMember(chat.id, user.id).execute(using bot).chatMember val chatMember: TChatMember = GetChatMember(chat.id, user.id).execute(using bot).chatMember
if chatMember eq null then false if chatMember eq null then false
else UserPermissionLevel(chatMember) >= UserPermissionLevel(permission) else UserPermissionLevel(chatMember) >= UserPermissionLevel(permission)
} }
/** If this [[TChat.Type]] is of the type specific.
*
* @since 2.0.0
*
* @return `true` if this [[TChat.type]] IS of the type. `false` otherwise.
*/
infix def ofType (ty: TChat.Type): Boolean =
chat.`type` == ty
/** If this [[TChat.Type]] is not of the type specific.
*
* @since 2.0.0
*
* @return `true` if this [[TChat.type]] IS NOT of the type specific. `false` otherwise.
*/
infix def notOfType (ty: TChat.Type): Boolean =
chat.`type` != ty
}} }}
object Message { extension (self: Message) { object Message { extension (self: TMessage) {
def entitiesSafe: List[MessageEntity] = def entitiesSafe: List[TMessageEntity] =
if self.entities == null then Nil else if self.entities == null then Nil else
self.entities.toList self.entities.toList
@ -318,7 +336,7 @@ object TelegramExtensions {
}} }}
object File { extension (self: File) { object File { extension (self: TFile) {
/** Alias of [[TelegramBot.getFileContent]] */ /** Alias of [[TelegramBot.getFileContent]] */
@throws[IOException] @throws[IOException]
@ -356,28 +374,28 @@ object TelegramExtensions {
bot.execute(self) bot.execute(self)
}} }}
/** A [[User]] instance with only a [[User.id]] is defined. /** A [[TUser]] instance with only a [[TUser.id]] is defined.
* *
* This is only for capabilities that some method need a [[User]] but only need its [[User.id]]. If * This is only for capabilities that some method need a [[TUser]] but only need its [[TUser.id]]. If
* you don't have a [[User]] instance for some reason, you can use this instead. * you don't have a [[TUser]] instance for some reason, you can use this instead.
* *
* Many methods may crashes on this class for this is highly mutilated. Use this only the method declares * Many methods may crashes on this class for this is highly mutilated. Use this only the method declares
* that using this is safe. * that using this is safe.
* *
* @since 1.0.0 * @since 1.0.0
*/ */
class LimboUser (id: Long) extends User(id) class LimboUser (id: Long) extends TUser(id)
/** A [[Chat]] instance with only a [[Chat.id]] is defined. /** A [[TChat]] instance with only a [[TChat.id]] is defined.
* *
* This is only for capabilities that some method need a [[Chat]] but only need its [[Chat.id]]. If * This is only for capabilities that some method need a [[TChat]] but only need its [[TChat.id]]. If
* you don't have a [[Chat]] instance for some reason, you can use this instead. * you don't have a [[TChat]] instance for some reason, you can use this instead.
* *
* Many methods may crashes on this class for this is highly mutilated. Use this only the method declares * Many methods may crashes on this class for this is highly mutilated. Use this only the method declares
* that using this is safe. * that using this is safe.
* *
* @since 1.0.0 * @since 1.0.0
*/ */
class LimboChat (val _id: Long) extends Chat() { class LimboChat (val _id: Long) extends TChat() {
override val id: java.lang.Long = _id override val id: java.lang.Long = _id
} }