From bfc94cbb6680c334de2efd88432af7ffbc2facc6 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Sat, 2 Sep 2023 15:05:16 +0530 Subject: [PATCH] feat: bot.myStatus - to simplify `my_chat_member` --- src/composer.ts | 90 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/src/composer.ts b/src/composer.ts index 2153dfe0..98fd46d2 100644 --- a/src/composer.ts +++ b/src/composer.ts @@ -78,6 +78,28 @@ interface CommandContextExtn { args: string[] } +interface StatusContextExtn { + /** Shorthand for old and new my_chat_member status */ + status: { + /** */ + change: StatusChange + /** Shorthand for update.my_chat_member.old_chat_member.status */ + old: tg.ChatMember['status'] + /** Shorthand for update.my_chat_member.new_chat_member.status */ + new: tg.ChatMember['status'] + } +} + +type StatusChange = + | 'blocked' + | 'unblocked' + | 'joined' + | 'left' + | 'banned' + | 'restricted' + | 'promoted' + | 'demoted' + const anoop = always(Promise.resolve()) export class Composer implements MiddlewareObj { @@ -161,7 +183,7 @@ export class Composer implements MiddlewareObj { Middleware & CommandContextExtn> > ) { - return this.use(Composer.command(command, ...fns)) + return this.use(Composer.command(command, ...fns)) } /** @@ -297,6 +319,23 @@ export class Composer implements MiddlewareObj { return this.command('settings', ...fns) } + /** + * Listen for the bot's status change in chats + * + * * `joined`, `left`, `promoted`, `demoted`, `banned`, `restricted` will only be triggered in non-private chats + * * `blocked`, `unblocked` will only be triggered in private chats + */ + myStatus( + change: MaybeArray, + ...fns: NonemptyReadonlyArray< + Middleware< + NarrowedContext & StatusContextExtn + > + > + ) { + return this.use(Composer.myStatus(change, Composer.compose(fns))) + } + middleware() { return this.handler } @@ -917,6 +956,35 @@ export class Composer implements MiddlewareObj { } } } + + static myStatus( + type: MaybeArray, + ...fns: NonemptyReadonlyArray< + Middleware< + NarrowedContext & StatusContextExtn + > + > + ): MiddlewareFn { + const changes = Array.isArray(type) ? type : [type] + const handler = Composer.compose(fns) + + return Composer.on('my_chat_member', async (ctx, next) => { + const status = { + new: ctx.myChatMember.new_chat_member.status, + old: ctx.myChatMember.old_chat_member.status, + } + + for (const change of changes) { + // todo: decide whether to normalise and fire for all matching changes, or just the first matching one + // ref: https://github.com/telegraf/telegraf/issues/1872 + if (checkStatusChange(change, ctx.chat.type, status.new, status.old)) + return handler( + Object.assign(ctx, { status: Object.assign(status, { change }) }), + next + ) + } + }) + } } function escapeRegExp(s: string) { @@ -950,6 +1018,7 @@ function getEntities(msg: tg.Message | undefined): tg.MessageEntity[] { if ('entities' in msg) return msg.entities ?? [] return [] } + function getText( msg: tg.Message | tg.CallbackQuery | undefined ): string | undefined { @@ -969,4 +1038,23 @@ function normaliseTextArguments(argument: MaybeArray, prefix = '') { .map((arg) => prefix && typeof arg === 'string' && !arg.startsWith(prefix) ? `${prefix}${arg}` : arg) } +function checkStatusChange( + change: StatusChange, + chatType: tg.Chat['type'], + current: tg.ChatMember['status'], + old: tg.ChatMember['status'] +) { + if (chatType === 'private') { + if (change === 'blocked') return current === 'kicked' + if (change === 'unblocked') return current === 'member' + } else { + if (change === 'joined') return old === 'left' || old === 'kicked' + if (change === 'banned') return current === 'kicked' + if (change === 'left') return current === 'left' + if (change === 'restricted') return current === 'restricted' + if (change === 'promoted') return current === 'administrator' + if (change === 'demoted') return old === 'administrator' + } +} + export default Composer