From 980d9008cfe96978ed7494760d0aec12917ef1ea Mon Sep 17 00:00:00 2001 From: Nikhil Jha Date: Mon, 22 Apr 2024 21:42:27 -0700 Subject: [PATCH] :sparkles: check plugin --- .transpire.py | 22 ++++++++- Dockerfile | 3 +- sopel/plugins/check.py | 100 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 sopel/plugins/check.py diff --git a/.transpire.py b/.transpire.py index a1d5876..af8b7e7 100644 --- a/.transpire.py +++ b/.transpire.py @@ -394,7 +394,19 @@ def objects(): "data": { "default.cfg": Path(__file__) .parent.joinpath("sopel", "default.cfg") - .read_text() + .read_text(), + }, + } + + # This feels a bit hacky but like... meh. + yield { + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": {"name": "sopel-plugins"}, + "data": { + "check.py": Path(__file__) + .parent.joinpath("sopel", "plugins", "check.py") + .read_text(), }, } @@ -425,6 +437,10 @@ def objects(): "name": "sopel-data", "mountPath": "/home/sopel/.sopel/", }, + { + "name": "sopel-plugins", + "mountPath": "/home/sopel/.sopel/plugins/", + }, ], } ], @@ -433,6 +449,10 @@ def objects(): "name": "sopel-config", "configMap": {"name": "sopel-config"}, }, + { + "name": "sopel-plugins", + "configMap": {"name": "sopel-plugins"}, + } ], }, }, diff --git a/Dockerfile b/Dockerfile index d5ae081..3432abf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,8 @@ COPY gamja/config.json /gamja/config.json FROM docker.io/python:3.11 AS sopel RUN adduser --disabled-password --gecos "" --home /home/sopel --uid 1000 sopel +RUN apt-get update && apt-get install -y --no-install-recommends libcrack2-dev && rm -rf /var/lib/apt/lists/* USER sopel ENV PATH="${PATH}:/home/sopel/.local/bin" -RUN python -m pip install pipx && pipx install git+https://github.com/sopel-irc/sopel.git#ab32aca08f7bf67d1ba754fdfc22a10ee5a442d0 +RUN python -m pip install pipx && pipx install git+https://github.com/sopel-irc/sopel.git#ab32aca08f7bf67d1ba754fdfc22a10ee5a442d0 && pipx inject sopel ocflib CMD [ "sopel", "start" ] diff --git a/sopel/plugins/check.py b/sopel/plugins/check.py new file mode 100644 index 0000000..29bcda5 --- /dev/null +++ b/sopel/plugins/check.py @@ -0,0 +1,100 @@ +"""Show information about OCF users.""" + +import grp +import string + +from ocflib.account import search +from ocflib.infra import ldap +from sopel import plugin + + +GROUP_COLOR_MAPPING = { + "ocf": "\x0314", # gray + "sorry": "\x0304", # red + "opstaff": "\x0303", # green + "ocfstaff": "\x0302", # blue + "ocfroot": "\x0307", # orange + "ocfapphost": "\x0310", # cyan + "ocfofficers": "\x0306", # purple + "ocfalumni": "\x0313", # pink +} + + +@plugin.command("check") +def check(bot, trigger): + """Print information about an OCF user.""" + user = trigger.group(1).strip() + attrs = search.user_attrs(user) + + if attrs is not None: + groups = [grp.getgrgid(attrs["gidNumber"]).gr_name] + groups.extend( + sorted(group.gr_name for group in grp.getgrall() if user in group.gr_mem), + ) + groups = [ + "{}{}\x0f".format(GROUP_COLOR_MAPPING.get(group, ""), group) + for group in groups + ] + + if "creationTime" in attrs: + created = attrs["creationTime"].strftime("%Y-%m-%d") + else: + created = "unknown" + + bot.reply( + "{user} ({uid}) | {name} | created {created} | groups: {groups}".format( + user=user, + uid=attrs["uidNumber"], + name=attrs["cn"][0], + created=created, + groups=", ".join(groups), + ), + ping=False, + ) + else: + bot.reply(f"{user} does not exist", ping=False) + + +def alphanum(word): + return "".join(c for c in word.lower() if c in string.ascii_lowercase) + + +@plugin.command("checkacct") +def checkacct(bot, trigger): + """Print matching OCF usernames.""" + search_term = trigger.group(1).strip() + keywords = search_term.split() + + if len(keywords) > 0: + search = "(&{})".format( + "".join( + # all keywords must match either uid or cn + "(|(uid=*{keyword}*)(cn=*{keyword}*))".format( + keyword=alphanum(keyword), + ) + for keyword in keywords + ), + ) + + with ldap.ldap_ocf() as c: + c.search( + ldap.OCF_LDAP_PEOPLE, + search, + attributes=("uid", "cn"), + size_limit=5, + ) + + if len(c.response) > 0: + bot.reply( + ", ".join( + sorted( + "{} ({})".format( + entry["attributes"]["uid"][0], + entry["attributes"]["cn"][0], + ) + for entry in c.response + ), + ), + ) + else: + bot.reply("no results found")