From: John Runyon Date: Sun, 12 Nov 2023 12:57:26 +0000 (-0700) Subject: add admin_channel X-Git-Url: https://jfr.im/git/erebus.git/commitdiff_plain/f6386fa7a5a628da6e931a82464bca6cf2e4aa35 add admin_channel --- diff --git a/TODO b/TODO index 31fcacf..9df8322 100644 --- a/TODO +++ b/TODO @@ -54,3 +54,7 @@ vim: expandtab sw=2 ts=2 - fix softdeps, if they're used through lib.mod() or parent.module() they break, need a `'mod' in modules` check somewhere - ctlmod.unload: track what modules are unloaded and return that info to caller + +- lookup User object by auth + modules should be able to (attempt to) look up a User object by auth, that way if the user is online + !clevel and !glevel can look up their existing object and adjust the permissions there diff --git a/bot.py b/bot.py index 51b7a0a..813151b 100644 --- a/bot.py +++ b/bot.py @@ -239,15 +239,20 @@ class Bot(object): if nick == self.nick: self.conn.send("WHO %s c%%cant,3" % (chan)) else: - user = self.parent.user(nick, justjoined=True) + user = self.parent.user(nick, send_who=True) chan.userjoin(user) user.join(chan) def _clientLeft(self, nick, chan): - if nick != self.nick: - gone = self.parent.user(nick).part(chan) - chan.userpart(self.parent.user(nick)) + if nick == self.nick: + for u in chan.users: + if u.nick != self.nick: + self._clientLeft(u.nick, chan) + else: + user = self.parent.user(nick) + gone = user.part(chan) + chan.userpart(user) if gone: - self.parent.user(nick).quit() + user.quit() del self.parent.users[nick.lower()] def _gotpart(self, pieces): nick = pieces[0].split('!')[0][1:] diff --git a/erebus.py b/erebus.py index 47f9a59..c161a42 100644 --- a/erebus.py +++ b/erebus.py @@ -228,17 +228,17 @@ class Erebus(object): #singleton to pass around def randbot(self): #get Bot() randomly return self.bots[random.choice(list(self.bots.keys()))] - def user(self, _nick, justjoined=False, create=True): + def user(self, _nick, send_who=False, create=True): nick = _nick.lower() + + if send_who and (nick not in self.users or not self.users[nick].isauthed()): + self.randbot().conn.send("WHO %s n%%ant,1" % (nick)) + if nick in self.users: return self.users[nick] elif create: user = self.User(_nick) self.users[nick] = user - - if justjoined: - self.randbot().conn.send("WHO %s n%%ant,1" % (nick)) - return user else: return None diff --git a/modlib.py b/modlib.py index a04dd78..eeb7c4e 100644 --- a/modlib.py +++ b/modlib.py @@ -50,11 +50,11 @@ class modlib(object): MASTER = 4 OP = 3 VOICE = 2 - #KNOWN = 1 is set above by glevels + FRIEND = 1 PUBLIC = 0 # Anyone (use glevel to control whether auth is needed) BANNED = -1 # The default reqclevel is PUBLIC, so any commands which needchan will be ignored from BANNED users unless the command reqclevel=-1 # [ 0 1 2 3 4 5 -1] - clevs = [None, 'Friend', 'Voice', 'Op', 'Master', 'Owner', None] + clevs = [None, 'Friend', 'Voice', 'Op', 'Master', 'Owner', 'Banned'] # messages WRONGARGS = "Wrong number of arguments." diff --git a/modules/admin_channel.py b/modules/admin_channel.py new file mode 100644 index 0000000..0f9f7fe --- /dev/null +++ b/modules/admin_channel.py @@ -0,0 +1,89 @@ +# Erebus IRC bot - Author: Erebus Team +# vim: fileencoding=utf-8 +# simple module example +# This file is released into the public domain; see http://unlicense.org/ + +# module info +modinfo = { + 'author': 'Erebus Team', + 'license': 'public domain', + 'compatible': [0], # compatible module API versions + 'depends': [], # other modules required to work properly? + 'softdeps': ['help'], # modules which are preferred but not required +} +# note: softdeps will be loaded before this module, IF not disabled in the configuration (autoload.module = 0) (and if it exists) +# however, if it is disabled it will be silently ignored, and if it is unloaded at runtime it won't cause this one to unload. +# +# basically, softdeps are things this module will use if available, but does not require (no errors will occur if it's not loaded) +# for example, @lib.help() will attempt to use the help module, but swallow errors if it is not loaded + +# preamble +import modlib +lib = modlib.modlib(__name__) +modstart = lib.modstart +modstop = lib.modstop + +# module code + +@lib.hook(clevel=lib.FRIEND) +@lib.help(None, "rejoin a channel (if the bot has been kicked)") +def rejoin(bot, user, chan, realtarget, *args): + bot.join(str(chan)) + bot.msg(user, "Rejoined.") + + +def _resolve_user(s): + if s.startswith("#"): + return lib.parent.User(s, s[1:]) + else: + return lib.parent.user(s, create=False) + + +def _resolve_level(s): + s = s.lower() + levels = ['unknown'] + [x.lower() for x in lib.clevs if x is not None] + if s in levels: + return levels.index(s) + try: + return int(s) + except: + pass + + +@lib.hook(('clevel','setlevel','chanlev'), clevel=lib.FRIEND) +@lib.help(' ', "adds or sets a user's channel access level", "Levels: Unknown, " + ', '.join([x for x in lib.clevs if x])) +@lib.argsEQ(2) +def clevel(bot, user, chan, realtarget, *args): + target = _resolve_user(args[0]) + level = _resolve_level(args[1]) + user_clevel = chan.levelof(user.auth) + + if target is None: + return "User not found (try #auth)" + if target.auth is None: + return "User is not authed" + if level is None or level < 0 or level > lib.COWNER: + return "Level is unknown" + + target_clevel = chan.levelof(target.auth) + + if not (target == user and level == 0) and user_clevel != lib.COWNER: + if user_clevel < lib.MASTER: + return "I'm afraid I can't let you do that. You can only reset your own level to 0." + if user_clevel <= target_clevel: + return "I'm afraid I can't let you do that. Your current access level is not higher than theirs." + if user_clevel <= level: + return "I'm afraid I can't let you do that. Your current access level is not higher than you are trying to set." + + chan.setlevel(target.auth, level) + return "Set #%s channel level to %s" % (target.auth, args[1]) + + +@lib.hook(glevel=lib.OWNER) +@lib.help('', "sets your own clevel on a channel") +@lib.argsEQ(1) +def forceclevel(bot, user, chan, realtarget, *args): + target = user.auth + level = _resolve_level(args[0]) + chan.setlevel(target, level) + return 'Your level on %s has been set to %d' % (chan, level) diff --git a/modules/admin_user.py b/modules/admin_user.py index cc069a6..3e4a02c 100644 --- a/modules/admin_user.py +++ b/modules/admin_user.py @@ -65,8 +65,11 @@ def glevel(bot, user, chan, realtarget, *args): user.msg("Level must -2, 0, or a positive integer") return - + # Skip checks if the user is setting their own level to 0, or if the user is OWNER if not (target == user and level == 0) and user.glevel != lib.OWNER: + if user.glevel <= lib.ADMIN: + user.msg("I'm afraid I can't let you do that. You can only reset your own level to 0.") + return if user.glevel <= target.glevel: user.msg("I'm afraid I can't let you do that. Your current access level is not higher than theirs.") return