# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence. """!zaproponuj -- file an idea for a command that does not exist yet. The other half of what the dispatcher does with an unrecognised word. That half is involuntary: it records what people mistyped. This one is somebody deliberately writing a note to whoever maintains the bot, which is why it is the only text this feature exports into the repository in full. The idea is stored against the command word it asks for, so twelve people asking for the same thing collapse into twelve rows under one name rather than twelve unrelated sentences. """ from __future__ import annotations from typing import TYPE_CHECKING, Final from signal_bot.animals import load_aliases from signal_bot.folding import fold from signal_bot.unknown import SUGGEST_PRIMARY, WORD_SHAPE if TYPE_CHECKING: from signal_bot.context import CommandContext from signal_bot.decorators import Decorator from signal_bot.registry import CommandRegistry COMMAND_NAME: Final = "suggest" DESCRIPTION: Final = "zaproponuj nową komendę, np. !zaproponuj !gekon zdjęcie gekona" USAGE: Final = f"Użycie: {SUGGEST_PRIMARY} !nazwa " NOT_A_NAME: Final = f"To nie wygląda jak nazwa komendy. {USAGE}" ALREADY: Final = "{word} już działa. Napisz !pomoc, żeby zobaczyć wszystkie komendy." THANKS: Final = "Zapisane: {word} — {body}" async def _handle(ctx: CommandContext, registry: CommandRegistry) -> None: """Validate one suggestion and file it, or explain why it was not.""" if not ctx.args: await ctx.reply(USAGE) return word = ctx.args[0] word = fold(word if word.startswith("!") else f"!{word}") if WORD_SHAPE.match(word) is None: await ctx.reply(NOT_A_NAME) return # Asked without a group, i.e. "does anything claim this anywhere?" -- # the same question pack_add asks before minting a label. A command # scoped to some other group must not be reported as free here, and # must not be named either. if registry.resolve(word) is not None: await ctx.reply(ALREADY.format(word=word)) return body = " ".join(ctx.args[1:]).strip() if not body: await ctx.reply(USAGE) return ctx.store.suggestions.record_suggestion(ctx.group_id, word, body, ctx.message.timestamp) await ctx.reply(THANKS.format(word=word, body=body)) def register_suggest_command( registry: CommandRegistry, *, decorate: Decorator | None = None, aliases: dict[str, list[str]] | None = None, ) -> None: """Register !zaproponuj on the registry it also reads. Registered with no ``groups``, and it has to stay that way: help_command looks its entry up by name for every group it renders, so a scoped command named in that table raises KeyError wherever it is not allowed. """ table = load_aliases() if aliases is None else aliases async def handler(ctx: CommandContext) -> None: await _handle(ctx, registry) wrapped = decorate(handler) if decorate is not None else handler registry.register( COMMAND_NAME, table[COMMAND_NAME], wrapped, DESCRIPTION, takes_args=True, )