From: John Runyon Date: Mon, 4 Sep 2023 02:23:29 +0000 (-0600) Subject: admin_user module to set users' glevel X-Git-Url: https://jfr.im/git/erebus.git/commitdiff_plain/25bf8fc584941be94d96d281f1a15d622e4e9b8f admin_user module to set users' glevel --- diff --git a/TODO b/TODO index 3fc9933..a915322 100644 --- a/TODO +++ b/TODO @@ -29,3 +29,5 @@ vim: expandtab sw=2 ts=2 - better config... or better yet just move non-DB-related config into the database - needs a better format if its used for generic module data; particularly because /\s#/ starts a comment instead of naming a channel - needs to retain comments when config file is saved + +- a module for administering channel users (copy from admin_user) and adding/removing channels diff --git a/erebus.py b/erebus.py index 0377d92..42a2f41 100644 --- a/erebus.py +++ b/erebus.py @@ -24,7 +24,10 @@ class Erebus(object): #singleton to pass around class User(object): def __init__(self, nick, auth=None): self.nick = nick - self.auth = auth + if auth is None: + self.auth = None + else: + self.auth = auth.lower() self.checklevel() self.chans = [] @@ -59,6 +62,23 @@ class Erebus(object): #singleton to pass around self.glevel = 0 return self.glevel + def setlevel(self, level, savetodb=True): + if savetodb: + if level != 0: + c = main.query("REPLACE INTO users (auth, level) VALUES (%s, %s)", (self.auth, level)) + else: + c = main.query("DELETE FROM users WHERE auth = %s", (self.auth,)) + if c == 0: # no rows affected + c = True # is fine + if c: + self.glevel = level + return True + else: + return False + else: + self.glevel = level + return True + def join(self, chan): if chan not in self.chans: self.chans.append(chan) def part(self, chan): @@ -117,6 +137,9 @@ class Erebus(object): #singleton to pass around return True else: return False + else: + self.levels[auth] = level + return True def userjoin(self, user, level=None): if user not in self.users: self.users.append(user) diff --git a/modlib.py b/modlib.py index ee94e9e..ae19fb5 100644 --- a/modlib.py +++ b/modlib.py @@ -29,16 +29,27 @@ class modlib(object): MANAGER = 99 ADMIN = 75 STAFF = 50 + KNOWN = 1 AUTHED = 0 # Users which have are known to be authed ANYONE = -1 # non-authed users have glevel set to -1 IGNORED = -2 # The default reqglevel is ANYONE, so any commands will be ignored from IGNORED users unless the command reglevel=-2 + glevs = { + 'OWNER': OWNER, + 'MANAGER': MANAGER, + 'ADMIN': ADMIN, + 'STAFF': STAFF, + 'KNOWN': KNOWN, + 'AUTHED': AUTHED, + 'ANYONE': ANYONE, + 'IGNORED': IGNORED, + } # (channel) access levels COWNER = 5 MASTER = 4 OP = 3 VOICE = 2 - KNOWN = 1 + #KNOWN = 1 is set above by glevels 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] diff --git a/modules/admin_user.py b/modules/admin_user.py new file mode 100644 index 0000000..cc069a6 --- /dev/null +++ b/modules/admin_user.py @@ -0,0 +1,80 @@ +# 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 + +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): + try: + i = int(s) + return i + except ValueError: + su = s.upper() + if su == "ANYONE": + su = "AUTHED" # resolve to 0 instead of -1 + if su in lib.glevs: + return lib.glevs[su] + return None + +@lib.hook(('glevel','glev','adduser','setuser'), needchan=False, glevel=1) +@lib.help(' ', "adds or sets a user's global level", "global level is any positive integer, 0 to delete a user, or -2 to ignore a user", "-2: ignored; 0: no special access (anyone); 1: known; 50: staff; 75: admin; 100: owner", "alternately you may use one of those keywords", "non-admins may only change their own level, and only to 0", "admins may only set lower access levels and may not set the access level of a user with higher access") +@lib.argsEQ(2) +def glevel(bot, user, chan, realtarget, *args): + target_s = args[0] + level_s = args[1] + target = _resolve_user(target_s) + level = _resolve_level(level_s) + + if target is None: + user.msg('User not found (try #auth)') + return + if target.auth is None: + user.msg('User is not authed') + return + if level is None: + user.msg("Level is unknown, must be an integer or one of %s" % (', '.join(lib.glevs.keys()))) + return + if level != -2 and level < 0: + user.msg("Level must -2, 0, or a positive integer") + return + + + if not (target == user and level == 0) and user.glevel != lib.OWNER: + 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 + if user.glevel <= level: + user.msg("I'm afraid I can't let you do that. Your current access level is not higher than you are trying to set.") + return + + if target.setlevel(level): + user.msg("The glevel of #%s has been updated successfully" % (target.auth)) + else: + user.msg("Failed to update the level")