diff --git a/LibWinDog/Database.py b/LibWinDog/Database.py index a57640a..0302538 100755 --- a/LibWinDog/Database.py +++ b/LibWinDog/Database.py @@ -14,19 +14,64 @@ class BaseModel(Model): class EntitySettings(BaseModel): language = CharField(null=True) + #country = ... + #timezone = ... class Entity(BaseModel): id = CharField(null=True) id_hash = CharField() settings = ForeignKeyField(EntitySettings, backref="entity", null=True) -class User(Entity): - pass +class File(BaseModel): + path = CharField() + content = BlobField() + owner = ForeignKeyField(Entity, backref="files") + class Meta: + indexes = ( + (('path', 'owner'), True), + ) + +#class BaseFilter(BaseModel): +# name = CharField(null=True) +# owner = ForeignKeyField(Entity, backref="filters") + +#class ScriptFilter(BaseFilter): +# script = TextField() + +#class StaticFilter(BaseFilter): +# response = TextField() + +class Filter(BaseModel): + name = CharField(null=True) + trigger = CharField(null=True) + output = CharField(null=True) + owner = ForeignKeyField(Entity, backref="filters") class Room(Entity): pass -Db.create_tables([EntitySettings, User, Room], safe=True) +UserToRoomDeferred = DeferredThroughModel() +FilterToRoomDeferred = DeferredThroughModel() + +class User(Entity): + rooms = ManyToManyField(Room, backref="users", through_model=UserToRoomDeferred) + +class UserToRoom(BaseModel): + user = ForeignKeyField(User, backref="room_links") + room = ForeignKeyField(Room, backref="user_links") + +class FilterToRoom(BaseModel): + filter = ForeignKeyField(Filter, backref="room_links") + room = ForeignKeyField(Room, backref="filter_links") + +UserToRoomDeferred.set_model(UserToRoom) +FilterToRoomDeferred.set_model(FilterToRoom) + +Db.create_tables([ + EntitySettings, File, Filter, + User, Room, + FilterToRoom, UserToRoom, +], safe=True) class UserSettingsData(): def __new__(cls, user_id:str=None) -> SafeNamespace: diff --git a/LibWinDog/Platforms/Mastodon/Mastodon.py b/LibWinDog/Platforms/Mastodon/Mastodon.py index e94b7ea..db5b793 100755 --- a/LibWinDog/Platforms/Mastodon/Mastodon.py +++ b/LibWinDog/Platforms/Mastodon/Mastodon.py @@ -46,7 +46,7 @@ def MastodonMakeInputMessageData(status:dict) -> InputMessageData: def MastodonHandler(event, Mastodon): if event["type"] == "mention": data = MastodonMakeInputMessageData(event["status"]) - OnInputMessageParsed(data) + on_input_message_parsed(data) call_endpoint(EventContext(platform="mastodon", event=event, manager=Mastodon), data) def MastodonSender(context:EventContext, data:OutputMessageData) -> None: @@ -67,5 +67,5 @@ def MastodonSender(context:EventContext, data:OutputMessageData) -> None: visibility=('direct' if context.event['status']['visibility'] == 'direct' else 'unlisted'), ) -RegisterPlatform(name="Mastodon", main=MastodonMain, sender=MastodonSender, manager_class=mastodon.Mastodon) +register_platform(name="Mastodon", main=MastodonMain, sender=MastodonSender, manager_class=mastodon.Mastodon) diff --git a/LibWinDog/Platforms/Matrix/Matrix.py b/LibWinDog/Platforms/Matrix/Matrix.py index f7ad5d5..c31b7a9 100755 --- a/LibWinDog/Platforms/Matrix/Matrix.py +++ b/LibWinDog/Platforms/Matrix/Matrix.py @@ -83,7 +83,7 @@ async def MatrixMessageHandler(room:nio.MatrixRoom, event:nio.RoomMessage) -> No if MatrixUsername == event.sender: return # ignore messages that come from the bot itself data = MatrixMakeInputMessageData(room, event) - OnInputMessageParsed(data) + on_input_message_parsed(data) call_endpoint(EventContext(platform="matrix", event=SafeNamespace(room=room, event=event), manager=MatrixClient), data) def MatrixSender(context:EventContext, data:OutputMessageData): @@ -97,5 +97,5 @@ def MatrixSender(context:EventContext, data:OutputMessageData): message_type="m.room.message", content={"msgtype": "m.text", "body": data.text_plain})) -RegisterPlatform(name="Matrix", main=MatrixMain, sender=MatrixSender, manager_class=(lambda:MatrixClient)) +register_platform(name="Matrix", main=MatrixMain, sender=MatrixSender, manager_class=(lambda:MatrixClient)) diff --git a/LibWinDog/Platforms/Telegram/Telegram.py b/LibWinDog/Platforms/Telegram/Telegram.py index 8c9a066..7503b99 100755 --- a/LibWinDog/Platforms/Telegram/Telegram.py +++ b/LibWinDog/Platforms/Telegram/Telegram.py @@ -68,7 +68,7 @@ def TelegramHandler(update:telegram.Update, context:CallbackContext=None) -> Non data = TelegramMakeInputMessageData(update.message) if (quoted := update.message.reply_to_message): data.quoted = TelegramMakeInputMessageData(quoted) - OnInputMessageParsed(data) + on_input_message_parsed(data) call_endpoint(EventContext(platform="telegram", event=update, manager=context), data) Thread(target=handler).start() @@ -107,7 +107,7 @@ def TelegramLinker(data:InputMessageData) -> SafeNamespace: linked.message = f"https://t.me/c/{room_id}/{message_id}" return linked -RegisterPlatform( +register_platform( name="Telegram", main=TelegramMain, sender=TelegramSender, diff --git a/LibWinDog/Platforms/Web/Web.py b/LibWinDog/Platforms/Web/Web.py index ad313a9..a08cbb0 100755 --- a/LibWinDog/Platforms/Web/Web.py +++ b/LibWinDog/Platforms/Web/Web.py @@ -55,7 +55,7 @@ class WebServerClass(BaseHTTPRequestHandler): def init_new_room(self, room_id:str=None): if not room_id: room_id = str(uuid7().hex) - WebQueues[room_id] = {}#{"0": queue.Queue()} + WebQueues[room_id] = {} #WebPushEvent(room_id, ".start", self.headers) #Thread(target=lambda:WebAntiDropEnqueue(room_id)).start() self.do_redirect(f"/{room_id}") @@ -65,24 +65,25 @@ class WebServerClass(BaseHTTPRequestHandler): self.send_header("Content-Type", "text/html; charset=UTF-8") self.send_header("Content-Encoding", "chunked") self.end_headers() - target = f"/{room_id}/{user_id}?page-target=1#load-target" if not is_redirected: - return self.wfile.write(f'''{web_html_prefix(head_extra=f'')} + target = f"/{room_id}/{user_id}?page-target=1#load-target" + self.wfile.write(f'''{web_html_prefix(head_extra=f'')}

WinDog 🐶️

Initializing... Click here if you are not automatically redirected.

'''.encode()) - self.wfile.write(f'''{web_html_prefix()} + else: + self.wfile.write(f'''{web_html_prefix()}

WinDog 🐶️

'''.encode()) - while True: - # TODO this apparently makes us lose threads, we should handle dropped connections? - try: - self.wfile.write(WebMakeMessageHtml(WebQueues[room_id][user_id].get(block=False), user_id).encode()) - except queue.Empty: - time.sleep(0.01) + while True: + # TODO this apparently makes us lose threads, we should handle dropped connections? + try: + self.wfile.write(WebMakeMessageHtml(WebQueues[room_id][user_id].get(block=False), user_id).encode()) + except queue.Empty: + time.sleep(0.01) def send_form_html(self, room_id:str, user_id:str): self.send_text_content((f'''{web_html_prefix("form no-margin")} @@ -158,7 +159,7 @@ def WebPushEvent(room_id:str, user_id:str, text:str, headers:dict[str:str]): settings = UserSettingsData(), ), ) - OnInputMessageParsed(data) + on_input_message_parsed(data) WebSender(context, ObjectUnion(data, {"from_user": True})) call_endpoint(context, data) @@ -183,7 +184,6 @@ def WebMain(path:str) -> bool: return True def WebSender(context:EventContext, data:OutputMessageData) -> None: - #WebQueues[context.event.room_id][context.event.user_id].put(data) for user_id in (room := WebQueues[context.event.room_id]): room[user_id].put(data) @@ -194,5 +194,5 @@ def WebAntiDropEnqueue(room_id:str, user_id:str): WebQueues[room_id][user_id].put(OutputMessageData()) time.sleep(WebConfig["anti_drop_interval"]) -RegisterPlatform(name="Web", main=WebMain, sender=WebSender) +register_platform(name="Web", main=WebMain, sender=WebSender) diff --git a/LibWinDog/Platforms/Web/requirements.txt b/LibWinDog/Platforms/Web/requirements.txt old mode 100644 new mode 100755 diff --git a/LibWinDog/Platforms/Web/windog.css b/LibWinDog/Platforms/Web/windog.css old mode 100644 new mode 100755 diff --git a/LibWinDog/Platforms/Web/windog.js b/LibWinDog/Platforms/Web/windog.js old mode 100644 new mode 100755 diff --git a/ModWinDog/Base/Base.py b/ModWinDog/Base/Base.py index cfb18f7..5d751b0 100755 --- a/ModWinDog/Base/Base.py +++ b/ModWinDog/Base/Base.py @@ -52,7 +52,7 @@ def cPing(context:EventContext, data:InputMessageData): #def cEval(context:EventContext, data:InputMessageData) -> None: # send_message(context, {"Text": choice(Locale.__('eval'))}) -RegisterModule(name="Base", endpoints=[ +register_module(name="Base", endpoints=[ SafeNamespace(names=["source"], handler=cSource), SafeNamespace(names=["config", "settings"], handler=cConfig, body=False, arguments={ "get": True, diff --git a/ModWinDog/Broadcast/Broadcast.py b/ModWinDog/Broadcast/Broadcast.py index 0038a56..34a46e0 100755 --- a/ModWinDog/Broadcast/Broadcast.py +++ b/ModWinDog/Broadcast/Broadcast.py @@ -12,10 +12,10 @@ def cBroadcast(context:EventContext, data:InputMessageData): if not (destination and text): return send_status_400(context, language) result = send_message(context, {"text_plain": text, "room": SafeNamespace(id=destination)}) - send_message(context, {"text_plain": "Executed."}) + send_status(context, 201, language) return result -RegisterModule(name="Broadcast", endpoints=[ +register_module(name="Broadcast", endpoints=[ SafeNamespace(names=["broadcast"], handler=cBroadcast, body=True, arguments={ "destination": True, }), diff --git a/ModWinDog/Codings/Codings.py b/ModWinDog/Codings/Codings.py index a7ef27b..1426d5b 100755 --- a/ModWinDog/Codings/Codings.py +++ b/ModWinDog/Codings/Codings.py @@ -41,7 +41,7 @@ def mCodings(context:EventContext, data:InputMessageData): except Exception: return send_status_error(context, language) -RegisterModule(name="Codings", group="Geek", endpoints=[ +register_module(name="Codings", group="Geek", endpoints=[ SafeNamespace(names=["encode", "decode"], handler=mCodings, body=False, quoted=False, arguments={ "algorithm": True, }, help_extra=(lambda endpoint, lang: f'{endpoint.module.get_string("algorithms", lang)}: {", ".join(CodingsAlgorithms)}.')), diff --git a/ModWinDog/Dumper/Dumper.py b/ModWinDog/Dumper/Dumper.py index f7905e9..340a043 100755 --- a/ModWinDog/Dumper/Dumper.py +++ b/ModWinDog/Dumper/Dumper.py @@ -6,13 +6,14 @@ from json import dumps as json_dumps # TODO work with links to messages +# TODO remove "wrong" objects like callables def cDump(context:EventContext, data:InputMessageData): if not (message := data.quoted): return send_status_400(context, data.user.settings.language) - text = json_dumps(message, default=(lambda obj: obj.__dict__), indent=" ") + text = json_dumps(message, default=(lambda obj: (obj.__dict__ if not callable(obj) else None)), indent=" ") return send_message(context, {"text_html": f'
{html_escape(text)}
'}) -RegisterModule(name="Dumper", group="Geek", endpoints=[ +register_module(name="Dumper", group="Geek", endpoints=[ SafeNamespace(names=["dump"], handler=cDump, quoted=True), ]) diff --git a/ModWinDog/Echo/Echo.py b/ModWinDog/Echo/Echo.py index 898cd16..eedad07 100755 --- a/ModWinDog/Echo/Echo.py +++ b/ModWinDog/Echo/Echo.py @@ -20,7 +20,7 @@ def cEcho(context:EventContext, data:InputMessageData): prefix = '' return send_message(context, {"text_html": (prefix + html_escape(text))}) -RegisterModule(name="Echo", endpoints=[ +register_module(name="Echo", endpoints=[ SafeNamespace(names=["echo"], handler=cEcho, body=True), ]) diff --git a/ModWinDog/Filters/Filters.py b/ModWinDog/Filters/Filters.py new file mode 100755 index 0000000..cebf7d2 --- /dev/null +++ b/ModWinDog/Filters/Filters.py @@ -0,0 +1,69 @@ +# ==================================== # +# WinDog multi-purpose chatbot # +# Licensed under AGPLv3 by OctoSpacc # +# ==================================== # + +def cFilters(context:EventContext, data:InputMessageData): + language = data.user.settings.language + if not check_room_admin(data.user): + return send_status(context, 403, language) + # action: create, delete, toggle + # * (input) handle, ignore <...> + # * (output) setscript <..., script> + # * (output) insert, remove <..., groupid, message> + #arguments = data.command.parse_arguments(4) + if not (action := data.command.arguments.action) or (action not in ["list", "create", "delete"]): + return send_status_400(context, language) + [room_id, filter_id, command_data] = ((None,) * 3) + for token in data.command.tokens[2:]: + if (not room_id) and (':' in token): + room_id = token + elif (not filter_id): + filter_id = token + elif (not command_data): + command_data = token + if not room_id: + room_id = data.room.id + if (action in ["delete"]) and (not filter_id): + return send_status_400(context, language) + match action: + case "list": + filters_list = "" + for filter in Filter.select().where(Filter.owner == room_id).namedtuples(): + filters_list += f"\n* {filter.id} — {filter.name or '[?]'}" + if filters_list: + return send_message(context, {"text_html": f"Filters for room {room_id}:{filters_list}"}) + else: + return send_status(context, 404, language, f"No filters found for the room {room_id}.", summary=False) + case "create": + ... + # TODO error message on name constraint violation + # TODO filter name validation (no spaces or special symbols, no only numbers) + if filter_id and (len(Filter.select().where((Filter.owner == room_id) & (Filter.name == filter_id)).tuples()) > 0): + return + else: + filter_id = Filter.create(name=filter_id, owner=room_id) + return send_status(context, 201, language, f"Filter with id {filter_id} in room {room_id} created successfully.", summary=False) + case "delete": + #try: + Filter.delete().where((Filter.owner == room_id) & ((Filter.id == filter_id) | (Filter.name == filter_id))).execute() + return send_status(context, 200, language) + #return send_status(context, 200, language, f"Filter {filter_id} for room {room_id} deleted successfully.", summary=False) + #except Exception: + # ... # TODO error and success message, actually check for if the item to delete existed + case "insert": # TODO + #output = Filter.select().where((Filter.owner == room_id) & ((Filter.id == filter_id) | (Filter.name == filter_id))).namedtuples().get().output + Filter.update(output=data.quoted).where((Filter.owner == room_id) & ((Filter.id == filter_id) | (Filter.name == filter_id))).execute() + case "remove": + ... + case "handle": + ... + case "ignore": + ... + +register_module(name="Filters", endpoints=[ + SafeNamespace(names=["filters"], handler=cFilters, quoted=False, arguments={ + "action": True, + }), +]) + diff --git a/ModWinDog/Filters/Filters.yaml b/ModWinDog/Filters/Filters.yaml new file mode 100755 index 0000000..139c451 --- /dev/null +++ b/ModWinDog/Filters/Filters.yaml @@ -0,0 +1,3 @@ +summary: + en: Tools for triggering actions on received messages. + diff --git a/ModWinDog/GPT/GPT.py b/ModWinDog/GPT/GPT.py index bc284c2..7016756 100755 --- a/ModWinDog/GPT/GPT.py +++ b/ModWinDog/GPT/GPT.py @@ -17,7 +17,7 @@ def cGpt(context:EventContext, data:InputMessageData): output += (completion.choices[0].delta.content or "") return send_message(context, {"text_plain": f"[🤖️ GPT]\n\n{output}"}) -RegisterModule(name="GPT", endpoints=[ +register_module(name="GPT", endpoints=[ SafeNamespace(names=["gpt", "chatgpt"], handler=cGpt, body=True), ]) diff --git a/ModWinDog/Hashing/Hashing.py b/ModWinDog/Hashing/Hashing.py index 7a3e512..171d0ca 100755 --- a/ModWinDog/Hashing/Hashing.py +++ b/ModWinDog/Hashing/Hashing.py @@ -13,7 +13,7 @@ def cHash(context:EventContext, data:InputMessageData): return send_message(context, { "text_html": f"
{html_escape(hashlib.new(algorithm, text_input.encode()).hexdigest())}
"}) -RegisterModule(name="Hashing", group="Geek", endpoints=[ +register_module(name="Hashing", group="Geek", endpoints=[ SafeNamespace(names=["hash"], handler=cHash, body=False, quoted=False, arguments={ "algorithm": True, }, help_extra=(lambda endpoint, lang: f'{endpoint.get_string("algorithms", lang)}: {", ".join(hashlib.algorithms_available)}.')), diff --git a/ModWinDog/Help/Help.py b/ModWinDog/Help/Help.py index 2285c8e..153bebe 100755 --- a/ModWinDog/Help/Help.py +++ b/ModWinDog/Help/Help.py @@ -25,7 +25,7 @@ def cHelp(context:EventContext, data:InputMessageData) -> None: text = text.strip() return send_message(context, {"text_html": text}) -RegisterModule(name="Help", group="Basic", endpoints=[ +register_module(name="Help", group="Basic", endpoints=[ SafeNamespace(names=["help"], handler=cHelp, arguments={ "endpoint": False, }), diff --git a/ModWinDog/Internet/Internet.py b/ModWinDog/Internet/Internet.py index 1d5e2bd..b20112c 100755 --- a/ModWinDog/Internet/Internet.py +++ b/ModWinDog/Internet/Internet.py @@ -142,7 +142,7 @@ def cSafebooru(context:EventContext, data:InputMessageData): except Exception: return send_status_error(context, language) -RegisterModule(name="Internet", endpoints=[ +register_module(name="Internet", endpoints=[ SafeNamespace(names=["embedded"], handler=cEmbedded, body=False, quoted=False), SafeNamespace(names=["web"], handler=cWeb, body=True), SafeNamespace(names=["translate"], handler=cTranslate, body=False, quoted=False, arguments={ diff --git a/ModWinDog/Multifun/Multifun.py b/ModWinDog/Multifun/Multifun.py index c2c255f..761e1eb 100755 --- a/ModWinDog/Multifun/Multifun.py +++ b/ModWinDog/Multifun/Multifun.py @@ -21,7 +21,7 @@ def mMultifun(context:EventContext, data:InputMessageData): text = choice(fun_strings["empty"]) return send_message(context, {"text_html": text, "ReplyTo": reply_to}) -RegisterModule(name="Multifun", endpoints=[ +register_module(name="Multifun", endpoints=[ SafeNamespace(names=["hug", "pat", "poke", "cuddle", "hands", "floor", "sessocto"], handler=mMultifun), ]) diff --git a/ModWinDog/Percenter/Percenter.py b/ModWinDog/Percenter/Percenter.py index 1859632..a76dc6c 100755 --- a/ModWinDog/Percenter/Percenter.py +++ b/ModWinDog/Percenter/Percenter.py @@ -15,7 +15,7 @@ def mPercenter(context:EventContext, data:InputMessageData): ) or context.endpoint.get_help_text(data.user.settings.language) ).format(RandomPercentString(), data.command.body)}) -RegisterModule(name="Percenter", endpoints=[ +register_module(name="Percenter", endpoints=[ SafeNamespace(names=["wish", "level"], handler=mPercenter, body=True), ]) diff --git a/ModWinDog/Scrapers/Scrapers.py b/ModWinDog/Scrapers/Scrapers.py index 9879090..a52ccab 100755 --- a/ModWinDog/Scrapers/Scrapers.py +++ b/ModWinDog/Scrapers/Scrapers.py @@ -123,7 +123,7 @@ def cCraiyonSelenium(context:EventContext, data:InputMessageData): closeSelenium(driver_index, driver) return result -RegisterModule(name="Scrapers", endpoints=[ +register_module(name="Scrapers", endpoints=[ SafeNamespace(names=["dalle"], handler=cDalleSelenium, body=True), SafeNamespace(names=["craiyon", "crayion"], handler=cCraiyonSelenium, body=True), ]) diff --git a/ModWinDog/Scripting/Scripting.py b/ModWinDog/Scripting/Scripting.py index 99fd80c..e1f753b 100755 --- a/ModWinDog/Scripting/Scripting.py +++ b/ModWinDog/Scripting/Scripting.py @@ -50,7 +50,7 @@ end)()"""))}) except (LuaError, LuaSyntaxError): return send_status_error(context, data.user.settings.language) -RegisterModule(name="Scripting", group="Geek", endpoints=[ +register_module(name="Scripting", group="Geek", endpoints=[ SafeNamespace(names=["lua"], handler=cLua, body=False, quoted=False), ]) diff --git a/ModWinDog/Start/Start.py b/ModWinDog/Start/Start.py index 12df3f4..68ee5ac 100755 --- a/ModWinDog/Start/Start.py +++ b/ModWinDog/Start/Start.py @@ -8,7 +8,7 @@ def cStart(context:EventContext, data:InputMessageData): text_html=context.endpoint.get_string( "start", data.user.settings.language).format(data.user.name))) -RegisterModule(name="Start", endpoints=[ +register_module(name="Start", endpoints=[ SafeNamespace(names=["start"], handler=cStart), ]) diff --git a/ModWinDog/System/System.py b/ModWinDog/System/System.py index 01527ba..9dc402b 100755 --- a/ModWinDog/System/System.py +++ b/ModWinDog/System/System.py @@ -28,12 +28,12 @@ def cExec(context:EventContext, data:InputMessageData): return send_message(context, {"text_html": f'
{html_escape(text)}
'}) def cRestart(context:EventContext, data:InputMessageData): - if (data.user.id not in AdminIds) and (data.user.tag not in AdminIds): + if not check_bot_admin(data.user): return send_status(context, 403, data.user.settings.language) open("./.WinDog.Restart.lock", 'w').close() return send_message(context, {"text_plain": "Bot restart queued."}) -RegisterModule(name="System", endpoints=[ +register_module(name="System", endpoints=[ SafeNamespace(names=["exec"], handler=cExec, body=True), SafeNamespace(names=["restart"], handler=cRestart), ]) diff --git a/README.md b/README.md index 68a0d72..de3bf6f 100755 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ The officially-hosted instances of this bot are, respectively: * [@WinDogBot](https://t.me/WinDogBot) on Telegram * [@windog:matrix.org](https://matrix.to/#/@windog:matrix.org) on Matrix * [@WinDog@botsin.space](https://botsin.space/@WinDog) on Mastodon (can also be used from any other Fediverse platform) +* [WinDog.octt.eu.org](https://windog.octt.eu.org) as a web chat In case you want to run your own instance: diff --git a/WinDog.py b/WinDog.py index 3bdb8fc..76887f3 100755 --- a/WinDog.py +++ b/WinDog.py @@ -127,6 +127,22 @@ def strip_url_scheme(url:str) -> str: tokens = urlparse.urlparse(url) return f"{tokens.netloc}{tokens.path}" +def parse_command_arguments(command, endpoint, count:int=None): + arguments = SafeNamespace() + body = command.body + index = 1 + for key in (endpoint.arguments or range(count)): + if (not count) and (endpoint.body != None) and (endpoint.arguments[key] == False): + continue # skip optional (False) arguments for now if command expects a body, they will be implemented later + try: + value = command.tokens[index] + body = body[len(value):].strip() + except IndexError: + value = None + arguments[str(key)] = value + index += 1 + return [arguments, body] + def TextCommandData(text:str, platform:str) -> CommandData|None: if not text: return None @@ -145,27 +161,17 @@ def TextCommandData(text:str, platform:str) -> CommandData|None: command.body = text[len(command.tokens[0]):].strip() if not (endpoint := obj_get(Endpoints, command.name)): return command # TODO shouldn't this return None? - if (endpoint.arguments): - command.arguments = SafeNamespace() - index = 1 - for key in endpoint.arguments: - if (endpoint.body != None) and (endpoint.arguments[key] == False): - continue # skip optional (False) arguments for now if command expects a body, they will be implemented later - try: - value = command.tokens[index] - command.body = command.body[len(value):].strip() - except IndexError: - value = None - command.arguments[key] = value - index += 1 + command.parse_arguments = (lambda count=None: parse_command_arguments(command, endpoint, count)) + if endpoint.arguments: + [command.arguments, command.body] = command.parse_arguments() return command -def OnInputMessageParsed(data:InputMessageData) -> None: +def on_input_message_parsed(data:InputMessageData) -> None: dump_message(data, prefix='> ') handle_bridging(send_message, data, from_sent=False) update_user_db(data.user) -def OnOutputMessageSent(output_data:OutputMessageData, input_data:InputMessageData, from_sent:bool) -> None: +def on_output_message_sent(output_data:OutputMessageData, input_data:InputMessageData, from_sent:bool) -> None: if (not from_sent) and input_data: output_data = ObjectUnion(output_data, {"room": input_data.room}) dump_message(output_data, prefix=f'<{"*" if from_sent else " "}') @@ -189,6 +195,14 @@ def handle_bridging(method:callable, data:MessageData, from_sent:bool): ObjectUnion(data, {"room": SafeNamespace(id=room_id)}, ({"text_plain": text_plain, "text_markdown": None, "text_html": text_html} if data.user else None)), from_sent=True) +def check_bot_admin(data:InputMessageData|UserData) -> bool: + user = (data.user or data) + return ((user.id in AdminIds) or (user.tag in AdminIds)) + +# TODO make this real +def check_room_admin(data:InputMessageData|UserData) -> bool: + return check_bot_admin(data) + def update_user_db(user:SafeNamespace) -> None: if not (user and user.id): return @@ -255,23 +269,23 @@ def send_message(context:EventContext, data:OutputMessageData, *, from_sent:bool if (not context.manager) and (manager := platform.manager_class): context.manager = call_or_return(manager) result = platform.sender(context, data) - OnOutputMessageSent(data, context.data, from_sent) + on_output_message_sent(data, context.data, from_sent) return result def send_notice(context:EventContext, data): - pass + ... def edit_message(context:EventContext, data:MessageData): - pass + ... def delete_message(context:EventContext, data:MessageData): - pass + ... -def RegisterPlatform(name:str, main:callable, sender:callable, linker:callable=None, *, event_class=None, manager_class=None, agent_info=None) -> None: +def register_platform(name:str, main:callable, sender:callable, linker:callable=None, *, event_class=None, manager_class=None, agent_info=None) -> None: Platforms[name.lower()] = SafeNamespace(name=name, main=main, sender=sender, linker=linker, event_class=event_class, manager_class=manager_class, agent_info=agent_info) app_log(f"{name}, ", inline=True) -def RegisterModule(name:str, endpoints:dict, *, group:str|None=None) -> None: +def register_module(name:str, endpoints:dict, *, group:str|None=None) -> None: module = SafeNamespace(group=group, endpoints=endpoints, get_string=(lambda query, lang=None: None)) if isfile(file := f"./ModWinDog/{name}/{name}.yaml"): module.strings = good_yaml_load(open(file, 'r').read()) diff --git a/WinDog.yaml b/WinDog.yaml index b5d2b2b..a7ca34c 100755 --- a/WinDog.yaml +++ b/WinDog.yaml @@ -17,7 +17,25 @@ statuses: 102: title: en: Processing + summary: + en: Your request has been accepted and is currently being processed. + it: La tua richiesta è stata accolta e sta venendo processata. icon: ⚙️ + 200: + title: + en: OK + summary: + en: Your request has completed successfully. + it: La tua richiesta è terminata con successo. + icon: 👌️ + 201: + title: + en: Created + it: Creato + summary: + en: The specified resource has been successfully created. + it: La risorsa specificata è stata creata con successo. + icon: 🪙️ 403: title: en: Forbidden