hemppa/modules/users.py

130 lines
5.1 KiB
Python

from modules.common.module import BotModule
import fnmatch
class MatrixModule(BotModule):
def __init__(self, name):
super().__init__(name)
self.classes = dict() # classname <-> pattern
async def matrix_message(self, bot, room, event):
args = event.body.split()
args.pop(0)
if len(args) == 1:
if args[0] == 'stats' or args[0] == 'roomstats':
stats = dict()
for name, pattern in self.classes.items():
stats[name] = 0
if args[0] == 'stats':
allusers = self.get_users(bot)
else:
allusers = self.get_users(bot, room.room_id)
total = len(allusers)
if total == 0:
await bot.send_text(room, "I don't see any users. How did this happen?")
return
matched = 0
for user in allusers:
for name, pattern in self.classes.items():
match = fnmatch.fnmatch(user, pattern)
if match:
stats[name] = stats[name] + 1
matched = matched + 1
stats['Matrix'] = total - matched
stats = dict(sorted(stats.items(), key=lambda item: item[1], reverse=True))
if args[0] == 'stats':
reply = f'I am seeing total {len(allusers)} users in {len(self.bot.client.rooms)} rooms:\n'
else:
reply = f'I am seeing {len(allusers)} users in this room:\n'
for name in stats:
if stats[name] > 0:
reply = reply + f' - {name}: {stats[name]} ({round(stats[name] / total * 100, 2)}%)\n'
await bot.send_text(room, reply)
return
if len(args) == 2:
if args[0] == 'list' or args[0] == 'listall':
bot.must_be_owner(event)
search_room = None
if args[0] == 'list':
search_room = room.room_id
allusers = self.get_users(bot, search_room)
users = fnmatch.filter(allusers, args[1])
if len(users):
await bot.send_text(room, ' '.join(users))
else:
await bot.send_text(room, 'No matching users found!')
return
if args[0] == 'kick':
bot.must_be_admin(room, event)
allusers = self.get_users(bot, room.room_id)
users = fnmatch.filter(allusers, args[1])
if len(users):
for user in users:
self.logger.debug(f"Kicking {user} from {room.room_id} as requested by {event.sender}")
await bot.client.room_kick(room.room_id, user)
else:
await bot.send_text(room, 'No matching users found!')
return
if args[0] == 'classify':
if args[1] == 'list':
await bot.send_text(room, f'Classes in use: {self.classes}.')
return
elif len(args) == 4:
if args[0] == 'classify':
if args[1] == 'add':
bot.must_be_owner(event)
name = args[2]
pattern = args[3]
self.classes[name] = pattern
await bot.send_text(room, f'Added class {name} pattern {pattern}.')
bot.save_settings()
return
elif len(args) == 3:
if args[0] == 'classify':
if args[1] == 'del':
bot.must_be_owner(event)
name = args[2]
del self.classes[name]
await bot.send_text(room, f'Deleted class {name}.')
bot.save_settings()
return
await bot.send_text(room, 'Unknown command - please see readme')
def get_users(self, bot, roomid=None):
allusers = []
for croomid in self.bot.client.rooms:
if not roomid or (roomid == croomid):
try:
users = self.bot.client.rooms[croomid].users
except (KeyError, ValueError) as e:
self.logger.warning(f"Couldn't get user list in room with id {croomid}, skipping: {repr(e)}")
continue
for user in users:
allusers.append(user)
allusers = list(dict.fromkeys(allusers)) # Deduplicate
return allusers
def search_users(self, bot, pattern):
allusers = self.get_users(self, bot)
return fnmatch.filter(allusers, pattern)
def help(self):
return 'User management tools'
def get_settings(self):
data = super().get_settings()
data["classes"] = self.classes
return data
def set_settings(self, data):
super().set_settings(data)
if data.get("classes"):
self.classes = data["classes"]
def matrix_start(self, bot):
super().matrix_start(bot)
self.bot = bot