Skip to content

Commit

Permalink
Merge pull request #416 from group-butler/feature/admincachetopg
Browse files Browse the repository at this point in the history
Feature/admincachetopg
  • Loading branch information
yangm97 committed Jan 19, 2019
2 parents 64a0f8c + a2a6a1c commit 637a77d
Show file tree
Hide file tree
Showing 35 changed files with 2,628 additions and 1,981 deletions.
1,307 changes: 802 additions & 505 deletions locales/en_GB.po

Large diffs are not rendered by default.

35 changes: 34 additions & 1 deletion lua/groupbutler/chat.lua
@@ -1,18 +1,51 @@
local log = require("groupbutler.logging")

local Chat = {}

local function p(self)
return getmetatable(self).__private
end

function Chat:new(obj, private)
assert(obj.id, "Chat: Missing obj.id")
assert(private.api, "Chat: Missing private.api")
assert(private.db, "Chat: Missing private.db")
setmetatable(obj, {
__index = self,
__index = function(s, index)
if self[index] then
return self[index]
end
return s:getProperty(index)
end,
__private = private,
})
return obj
end

function Chat:getProperty(index)
local property = rawget(self, index)
if property == nil then
property = p(self).db:getChatProperty(self, index)
if property == nil then
local ok = p(self).api:getChat(self.id)
if not ok then
log.warn("Chat: Failed to get {property} for {id}", {
property = index,
id = self.id,
})
return nil
end
for k,v in pairs(ok) do
self[k] = v
end
self:cache()
property = rawget(self, index)
end
self[index] = property
end
return property
end

function Chat:cache()
p(self).db:cacheChat(self)
end
Expand Down
107 changes: 107 additions & 0 deletions lua/groupbutler/chatmember.lua
@@ -0,0 +1,107 @@
local log = require("groupbutler.logging")
local User = require("groupbutler.user")

local ChatMember = {}

local function p(self)
return getmetatable(self).__private
end

function ChatMember:new(obj, private)
assert(obj.chat, "ChatMember: Missing obj.chat")
assert(obj.user, "ChatMember: Missing obj.user")
assert(private.db, "ChatMember: Missing private.db")
assert(private.api, "ChatMember: Missing private.api")
setmetatable(obj, {
__index = function(s, index)
if self[index] then
return self[index]
end
return s:getProperty(index)
end,
__private = private,
})
return obj
end

function ChatMember:getProperty(index)
local property = rawget(self, index)
if property == nil then
property = p(self).db:getChatMemberProperty(self, index)
if property == nil then
local ok = p(self).api:getChatMember(self.chat.id, self.user.id)
if not ok then
log.warn("ChatMember: Failed to get {property} for {chat_id}, {user_id}", {
property = index,
chat_id = self.chat.id,
user_id = self.user.id,
})
return nil
end
for k,v in pairs(ok) do
self[k] = v
if k == "user" then
User:new(self.user, p(self))
end
end
self:cache()
property = rawget(self, index)
end
self[index] = property
end
return property
end

function ChatMember:cache()
p(self).db:cacheChatMember(self)
end

function ChatMember:isAdmin()
if self.chat.type == "private" then -- This should never happen but...
return false
end
return self.status == "creator" or self.status == "administrator"
end

function ChatMember:can(permission)
if self.chat.type == "private" then -- This should never happen but...
return false
end
if self.status == "creator"
or (self.status == "administrator" and self[permission]) then
return true
end
return false
end

function ChatMember:ban(until_date)
local ok, err = p(self).api:kickChatMember(self.chat.id, self.user.id, until_date)
if not ok then
return nil, p(self).api_err:trans(err)
end
return ok
end

function ChatMember:kick()
local ok, err = p(self).api:kickChatMember(self.chat.id, self.user.id)
if not ok then
return nil, p(self).api_err:trans(err)
end
p(self).api:unbanChatMember(self.chat.id, self.user.id)
return ok
end

function ChatMember:mute(until_date)
local ok, err = p(self).api:restrictChatMember({
chat_id = self.chat.id,
user_id = self.user.id,
until_date = until_date,
can_send_messages = false,
})
if not ok then
return nil, p(self).api_err:trans(err)
end
return ok
end

return ChatMember
75 changes: 51 additions & 24 deletions lua/groupbutler/main.lua
Expand Up @@ -7,6 +7,7 @@ local plugins = require "groupbutler.plugins"
local Message = require "groupbutler.message"
local User = require "groupbutler.user"
local Chat = require "groupbutler.chat"
local ChatMember = require "groupbutler.chatmember"
local storage = require "groupbutler.storage"
local locale = require "groupbutler.languages"
local api_err = require "groupbutler.api_errors"
Expand Down Expand Up @@ -41,21 +42,43 @@ function _M:new(update_obj)
end

local function inject_message_methods(message, update)
if message.from then
message.from = {
user = message.from,
chat = message.chat,
}
end
Message:new(message, update)
if message.from then -- Sender is empty for messages sent to channels
User:new(message.from, update):cache()
if message.from then
if message.from.user then -- Sender is empty for messages sent to channels
User:new(message.from.user, update):cache()
end
if message.from.chat then
Chat:new(message.chat, update)--:cache()
end
if message.from.user and message.from.chat then
ChatMember:new(message.from, update)--:cache()
end
end
if message.forward_from then
User:new(message.forward_from, update):cache()
end
if message.chat then
Chat:new(message.chat, update)
if message.new_chat_members then
for k,v in pairs(message.new_chat_members) do
message.new_chat_members[k] = {
user = v,
chat = message.chat,
}
User:new(message.new_chat_members[k].user, update)
Chat:new(message.new_chat_members[k].chat, update)
ChatMember:new(message.new_chat_members[k], update):cache()
end
end
end

local function add_message_methods(object, update)
local message_objects = {
"message", "edited_message", "channel_post", -- Possible messages inside updates
"message", --[["edited_message",]] "channel_post", -- Possible messages inside updates
"reply_to_message", "pinned_message", -- Possible messages inside messages
}
for _, message in pairs(message_objects) do
Expand All @@ -75,9 +98,9 @@ local function collect_stats(self)
local red = self.red
local u = self.u
local now = os.time(os.date("*t"))
if msg.chat.type ~= 'private' and msg.chat.type ~= 'inline' and msg.from then
red:hset('chat:'..msg.chat.id..':userlast', msg.from.id, now) --last message for each user
red:hset('bot:chats:latsmsg', msg.chat.id, now) --last message in the group
if msg.from.chat.type ~= 'private' and msg.from.chat.type ~= 'inline' and msg.from.user then
red:hset('chat:'..msg.from.chat.id..':userlast', msg.from.user.id, now) --last message for each user
red:hset('bot:chats:latsmsg', msg.from.chat.id, now) --last message in the group
end
u:metric_incr("messages_processed_count")
u:metric_set("message_timestamp_distance_sec", now - msg.date)
Expand Down Expand Up @@ -121,21 +144,21 @@ local function on_msg_receive(self, callback) -- The fn run whenever a message i
end

-- Set chat language
i18n:setLanguage(red:get('lang:'..msg.chat.id))
i18n:setLanguage(red:get('lang:'..msg.from.chat.id))

-- Do not process messages from normal groups
if msg.chat.type == 'group' then
api:sendMessage(msg.chat.id, i18n([[Hello everyone!
if msg.from.chat.type == 'group' then
api:sendMessage(msg.from.chat.id, i18n([[Hello everyone!
My name is %s, and I'm a bot made to help administrators in their hard work.
Unfortunately I can't work in normal groups. If you need me, please ask the creator to convert this group to a supergroup and then add me again.
]]):format(bot.first_name))
api:leaveChat(msg.chat.id)
api:leaveChat(msg.from.chat.id)
if config.bot_settings.stream_commands then
log.info('Bot was added to a normal group {by_name} [{from_id}] -> [{chat_id}]',
{
by_name=msg.from.first_name,
from_id=msg.from.id,
chat_id=msg.chat.id,
by_name=msg.from.user.first_name,
from_id=msg.from.user.id,
chat_id=msg.from.chat.id,
})
end
return true
Expand Down Expand Up @@ -167,21 +190,21 @@ Unfortunately I can't work in normal groups. If you need me, please ask the crea

if blocks then
-- init agroup if the bot wasn't aware to be in
if msg.chat.id < 0
and msg.chat.type ~= 'inline'
and red:exists('chat:'..msg.chat.id..':settings') == 0
if msg.from.chat.id < 0
and msg.from.chat.type ~= 'inline'
and red:exists('chat:'..msg.from.chat.id..':settings') == 0
and not msg.service then
u:initGroup(msg.chat.id)
u:initGroup(msg.from.chat)
end

-- print some info in the terminal
if config.bot_settings.stream_commands then
log.info('{trigger} {from_name} [{from_id}] -> [{chat_id}]',
{
trigger=trigger,
from_name=msg.from.first_name,
from_id=msg.from.id,
chat_id=msg.chat.id,
from_name=msg.from.user.first_name,
from_id=msg.from.user.id,
chat_id=msg.from.chat.id,
})
end

Expand Down Expand Up @@ -230,7 +253,7 @@ function _M:process()
function_key = 'onEditedMessage'
end

self.message = self.message or self.edited_message
self.message = self.message or self.edited_message -- TODO: undo this

local service_messages = {
"left_chat_member", "new_chat_member", "new_chat_photo", "delete_chat_photo", "group_chat_created",
Expand Down Expand Up @@ -291,7 +314,11 @@ function _M:process()
self.message.message_id = self.message.message.message_id
self.message.chat = self.message.message.chat
else --when the inline keyboard is sent via the inline mode
self.message.chat = {type = 'inline', id = self.message.from.id, title = self.message.from.first_name}
self.message.chat = {
type = 'inline',
id = self.message.from.user.id,
title = self.message.from.user.first_name
}
self.message.message_id = self.message.inline_message_id
end
self.message.date = os.time()
Expand Down

0 comments on commit 637a77d

Please sign in to comment.