Release 2.4

[NEW] command /link to retrieve chat invite link
[NEW] commands /mute, /unmute, /ban, /unban, /promote to manage chats
[NEW] command /leave! to leave group as owner
[FIX] tested and fixed some chat commands
This commit is contained in:
annelin 2020-03-09 19:56:13 +02:00
parent edfae83b8f
commit c3197cd000

View file

@ -1,3 +1,17 @@
DEFAULTS = {
lib_path: 'lib/',
verbosity: 2,
loglevel: :debug,
client: {api_id: 50322, api_hash: '9ff1a639196c0779c86dd661af8522ba', use_chat_info_database: false},
content: {path: '', link: '', upload: ''}
}
PERMISSIONS = {
admin: {can_be_edited: true, can_change_info: true, can_post_messages: true, can_edit_messages: true, can_delete_messages: true, can_invite_users: true, can_restrict_members: true, can_pin_messages: true, can_promote_members: false},
member: TD::Types::ChatPermissions.new(can_send_messages: true, can_send_media_messages: true, can_send_polls: true, can_send_other_messages: true, can_add_web_page_previews: true, can_change_info: true, can_invite_users: true, can_pin_messages: true),
readonly: TD::Types::ChatPermissions.new(can_send_messages: false, can_send_media_messages: false, can_send_polls: false, can_send_other_messages: false, can_add_web_page_previews: false, can_change_info: false, can_invite_users: false, can_pin_messages: false),
}
HELP_GATE_CMD = %q{Available commands:
/login phone — sign in
/logout — sign out
@ -26,9 +40,15 @@ HELP_CHAT_CMD= %q{Available commands:
/block — blacklist current user
/unblock — unblacklist current user
/invite id or @username — add user to current chat
/link — get invite link for current chat
/kick id or @username — remove user from current chat
/ban id or @username [hours] — restrict @username from current chat for [hours] or forever
/mute id or @username [hours] — mute user in current chat
/unmute id or @username — unrestrict user from current chat
/ban id or @username [hours] — restrict @username from current chat
/unban id or @username — unbans @username in current chat (and devotes from admins)
/promote id or @username — promote user to admin in current chat
/leave — leave current chat
/leave! — leave current chat (for owners)
/close — close current secret chat
/delete — delete current chat from chat list
/members [query] — search members [by optional query] in current chat (requires admin rights)
@ -37,18 +57,16 @@ HELP_CHAT_CMD= %q{Available commands:
class TelegramClient
attr_reader :session, :state
@@config = {loglevel: :debug, verbosity: 2, lib_path: 'lib/', client: {api_id: 50322, api_hash: '9ff1a639196c0779c86dd661af8522ba', use_chat_info_database: false}, content: {path:'',link:'',upload:''}} # defaults
## configure tdlib (when valid tdlib params specified) or zhabogram
def self.configure(**config)
@@config = @@config.merge(config)
@@config = DEFAULTS.merge(config)
TD.config.update(config[:tdlib])
TD::Api.set_log_verbosity_level(@@config[:tdlib_verbosity])
end
## initialize telegram client instance (xmpp = XMPP stream, jid = user's jid , login = user's telegram login (for now, it is phone number)
def initialize(xmpp, jid, **session)
return unless @@config
@logger = Logger.new(STDOUT, level: @@config[:loglevel], progname: 'TelegramClient: %s | %s' % [jid, session[:login]] )
@xmpp = xmpp
@jid = jid
@ -225,6 +243,7 @@ class TelegramClient
return @cache[:chats][id], @cache[:users][id]
end
## get last messages from specified chat
def get_lastmessages(id, query=nil, from=nil, count=1)
result = @telegram.search_chat_messages(id, query.to_s, from.to_i, 0, 0, count.to_i, TD::Types::SearchMessagesFilter::Empty.new).value
return (result) ? result.messages : []
@ -247,15 +266,17 @@ class TelegramClient
when TD::Types::UserStatus::Offline then show, status = (Time.now.getutc.to_i-status.was_online.to_i<3600) ? :away : :xa,
DateTime.strptime((status.was_online+Time.now.getlocal(@session[:timezone]).utc_offset).to_s,'%s').strftime("Last seen at %H:%M %d/%m/%Y")
end
@xmpp.send_presence(@jid, id, nil, show, status, nil, photo, immed)
return @xmpp.send_presence(@jid, id, nil, show, status, nil, photo, immed)
end
## send outgoing message to telegram user
def process_outgoing_message(id, text)
return if self.process_command(id, text.split.first, text.split[1..-1]) or not self.online? # try to execute commands
@logger.warn 'Sending message to chat %s' % id
message, reply = self.format_input(text)
@telegram.send_message(id, reply, nil, nil, message).rescue{|e| @xmpp.send_message(@jid, id, "Not sent: %s" % e)}
reply = text.lines[0].scan(/\d+/).first.to_i if text.lines[0] =~ /^> ?[0-9]{10}/
text = TD::Types::FormattedText.new(text: !reply ? text : text.lines[1..-1].join, entities: [])
message = TD::Types::InputMessageContent::Text.new(text: text, disable_web_page_preview: false, clear_draft: false)
return (id) ? @telegram.send_message(id, reply.to_i, nil, nil, message).rescue{|e| @xmpp.send_message(@jid, id, "Not sent: %s" % e)} : message
end
## /commands (some telegram actions)
@ -278,7 +299,7 @@ class TelegramClient
else # chat commands
case cmd
when '/d' then @telegram.delete_messages(chat.id, self.get_lastmessages(chat.id, nil, @me.id, args[0]||1).map(&:id), true) # delete message
when '/s' then @telegram.edit_message_text(chat.id, self.get_lastmessages(chat.id, nil, @me.id, 1).first.id, nil, self.format_input(args.join(' ')).first) # edit message
when '/s' then @telegram.edit_message_text(chat.id, self.get_lastmessages(chat.id, nil, @me.id, 1).first.id, nil, self.process_outgoing_message(nil, args.join(' '))) # edit message
when '/add' then @telegram.search_public_chat(args[0]).then{|chat| @xmpp.send_presence(@jid, chat.id, :subscribe)}.wait # add @contact
when '/join' then @telegram.join_chat_by_invite_link(args[0]) # join https://t.me/publichat
when '/supergroup' then @telegram.create_new_supergroup_chat(args[0], false, args[1..-1].join(' '), nil) # create new supergroup
@ -287,14 +308,20 @@ class TelegramClient
when '/group' then @telegram.create_new_basic_group_chat(chat.id, args[0]) # create group chat with current user
when '/block' then @telegram.block_user(chat.id) # blacklists current user
when '/unblock' then @telegram.unblock_user(chat.id) # unblacklists current user
when '/invite' then @telegram.add_chat_member(chat.id, self.get_contact(args[0]).first.id, 100) # invite @username to current groupchat
when '/kick' then @telegram.set_chat_member_status(chat.id, self.get_contact(args[0]).first.id, self.format_restrict()) # kick @username from current group chat
when '/ban' then @telegram.set_chat_member_status(chat.id, self.get_contact(args[0]).first.id, self.format_restrict(true, args[1])) # ban @username from current chat [for N hours]
when '/leave' then @telegram.leave_chat(chat.id).then{@xmpp.send_presence(@jid, id, :unsubscribed)} # leave current chat
when '/close' then @telegram.close_secret_chat(chat.type.secret_id).then{@xmpp.send_presence(@jid, id, :unsubscribed)} # close secret chat
when '/delete' then @telegram.delete_chat_history(chat.id, true, true).then{@xmpp.send_presence(@jid, id, :unsubscribed)} # delete current chat
when '/members' then @telegram.search_chat_members(chat.id, args[0], 9999, TD::Types::ChatMembersFilter::Members.new).then{|m| @xmpp.send_message(@jid, chat.id, (m.members.map do |u| "%s | role: %s" % [self.format_contact(u.user_id), u.status.class] end).join("\n")) } # chat members
when '/search' then @telegram.search_chat_messages(chat.id, args[0].to_s, 0, 0, 0, args[1].to_i||100, TD::Types::SearchMessagesFilter::Empty.new).value.messages.reverse.each{|m| @xmpp.send_message(@jid, chat.id, self.format_message(nil,nil,nil,msg))} # search
when '/invite' then @telegram.add_chat_member(chat.id, self.get_contact(args[0]).first.id, 100) # invite @username to current groupchat
when '/link' then @telegram.generate_chat_invite_link(chat.id).then{|link| @xmpp.send_message(@jid, chat.id, link.invite_link)} # get link to current chat
when '/kick' then @telegram.set_chat_member_status(chat.id, self.get_contact(args[0]).first.id, TD::Types::ChatMemberStatus::Left.new()) # kick @username
when '/mute' then @telegram.set_chat_member_status(chat.id, self.get_contact(args[0]).first.id, TD::Types::ChatMemberStatus::Restricted.new(is_member: true, restricted_until_date: self.format_bantime(args[0]), permissions: PERMISSIONS[:readonly])) # mute @username [n hours]
when '/unmute' then @telegram.set_chat_member_status(chat.id, self.get_contact(args[0]).first.id, TD::Types::ChatMemberStatus::Restricted.new(is_member: true, restricted_until_date: 0, permissions: PERMISSIONS[:member])) # unmute @username
when '/ban' then @telegram.set_chat_member_status(chat.id, self.get_contact(args[0]).first.id, TD::Types::ChatMemberStatus::Banned.new(banned_until_date: self.format_bantime(args[0]))) # ban @username [n hours]
when '/unban' then @telegram.set_chat_member_status(chat.id, self.get_contact(args[0]).first.id, TD::Types::ChatMemberStatus::Member.new()) # unban @username
when '/promote' then @telegram.set_chat_member_status(chat.id, self.get_contact(args[0]).first.id, TD::Types::ChatMemberStatus::Administrator.new(custom_title: args[0].to_s, **PERMISSIONS[:admin])) # promote @username to admin
when '/leave' then @telegram.leave_chat(chat.id).then{@xmpp.send_presence(@jid, chat.id, :unsubscribed)} # leave current chat
when '/leave!' then @telegram.delete_supergroup(chat.type.supergroup_id).then{@xmpp.send_presence(@jid, chat.id, :unsubscribed)}.rescue{|e| puts e.to_s} # leave current chat (for owners)
when '/close' then @telegram.close_secret_chat(chat.type.secret_id).then{@xmpp.send_presence(@jid, chat.id, :unsubscribed)} # close secret chat
when '/delete' then @telegram.delete_chat_history(chat.id, true, true).then{@xmpp.send_presence(@jid, chat.id, :unsubscribed)} # delete current chat
when '/search' then @telegram.get_messages(chat.id, self.get_lastmessages(chat.id, args[0], 0, args[1]||100).map(&:id)).value.messages.reverse.each{|msg| @xmpp.send_message(@jid, chat.id, self.format_message(chat.id,msg,false))} # message search
when '/help' then @xmpp.send_message(@jid, id, HELP_CHAT_CMD)
else return # continue
end
@ -305,7 +332,7 @@ class TelegramClient
#########################################################################
# formatting functions #################################################
#########################################################################
def format_contact(id)
return if not id or id == 0
chat, user = self.get_contact(id)
@ -325,31 +352,24 @@ class TelegramClient
return str
end
def format_input(text)
reply = text.lines[0].scan(/\d+/).first.to_i if text.lines[0] =~ /^> ?[0-9]{10}/ # quotes
file = TD::Types::InputFile::Remote.new(id: text) if text.start_with? @@config[:content][:upload] # attaches
text = TD::Types::FormattedText.new(text: (reply or file) ? text.lines[1..-1].join : text, entities: []) # remove first line (quotes/files)
input = (file) ? TD::Types::InputMessageContent::Document.new(document: file, caption: text) : TD::Types::InputMessageContent::Text.new(text: text, disable_web_page_preview: false, clear_draft: false) # message
return input, reply.to_i
end
def format_forward(fwd)
str = case fwd.origin
when TD::Types::MessageForwardOrigin::User then self.format_contact(fwd.origin.sender_user_id)
when TD::Types::MessageForwardOrigin::HiddenUser then fwd.origin.sender_name
when TD::Types::MessageForwardOrigin::Channel then [self.format_contact(fwd.origin.chat_id), fwd.origin.author_signature].join(' ')
end
return str
end
def format_content(file, fname)
str = "%s (%d kbytes) | %s/%s%s" % [fname, file.size/1024, @@config[:content][:link], Digest::SHA256.hexdigest(file.remote.id), File.extname(fname).to_s]
return str
end
def format_restrict(ban=false, hours=0)
till = (hours==0) ? 0 : Time.now.getutc.to_i + hours.to_i*3600
return (ban) ? TD::Types::ChatMemberStatus::Banned.new(banned_until_date: till) : TD::Types::ChatMemberStatus::Left.new
def format_forward(fwd)
str = case fwd.origin
when TD::Types::MessageForwardOrigin::User then self.format_contact(fwd.origin.sender_user_id)
when TD::Types::MessageForwardOrigin::HiddenUser then fwd.origin.sender_name
when TD::Types::MessageForwardOrigin::Channel then [self.format_contact(fwd.origin.chat_id), fwd.origin.author_signature].join ' '
end
return str
end
def format_bantime(hours=0)
now = Time.now.getutc.to_i
till = now + hours.to_i*3600
return (hours.to_i>0) ? till : 0
end
end