Support commands

Closes https://git.autonomic.zone/decentral1se/xbotlib/issues/12.
This commit is contained in:
Luke Murphy 2021-01-14 23:45:23 +01:00
parent d8bbacc258
commit a463aa91f1
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC
5 changed files with 73 additions and 3 deletions

View File

@ -7,6 +7,7 @@
- Remove `--no-input` option and detect it automatically ([#14](https://git.autonomic.zone/decentral1se/xbotlib/issues/14)) - Remove `--no-input` option and detect it automatically ([#14](https://git.autonomic.zone/decentral1se/xbotlib/issues/14))
- Refer to `jid` as `account` from now on both internally and externally ([#14](https://git.autonomic.zone/decentral1se/xbotlib/issues/14)) - Refer to `jid` as `account` from now on both internally and externally ([#14](https://git.autonomic.zone/decentral1se/xbotlib/issues/14))
- `bot.conf` -> `$name.conf` ([#3](https://git.autonomic.zone/decentral1se/xbotlib/issues/3)) - `bot.conf` -> `$name.conf` ([#3](https://git.autonomic.zone/decentral1se/xbotlib/issues/3))
- Support `!` style commands ([#12](https://git.autonomic.zone/decentral1se/xbotlib/issues/12))
# xbotlib 0.7.1 (2021-01-13) # xbotlib 0.7.1 (2021-01-13)

View File

@ -95,6 +95,20 @@ Attributes:
- **nickname**: the nickname of the sender - **nickname**: the nickname of the sender
- **type**: the type of message (`chat` or `groupchat`) - **type**: the type of message (`chat` or `groupchat`)
## Documenting your bot
Add a `help = "my help"` to your `Bot` class like so.
```python
class MyBot(Bot):
help = "My help"
```
The bot will then respond to:
- `!uptime` commands in direct messages
- `<nick>:!uptime` commands in group chats (use your own nick)
## Configure your bot ## Configure your bot
All the ways you can pass configuration details to your bot. All the ways you can pass configuration details to your bot.

17
poetry.lock generated
View File

@ -85,6 +85,17 @@ mccabe = ">=0.6.0,<0.7.0"
pycodestyle = ">=2.6.0a1,<2.7.0" pycodestyle = ">=2.6.0a1,<2.7.0"
pyflakes = ">=2.2.0,<2.3.0" pyflakes = ">=2.2.0,<2.3.0"
[[package]]
name = "humanize"
version = "3.2.0"
description = "Python humanize utilities"
category = "main"
optional = false
python-versions = ">=3.6"
[package.extras]
tests = ["freezegun", "pytest", "pytest-cov"]
[[package]] [[package]]
name = "importlib-metadata" name = "importlib-metadata"
version = "3.3.0" version = "3.3.0"
@ -259,7 +270,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.6" python-versions = "^3.6"
content-hash = "077e5cd9d069cbe55c52ca17d9b401be8338b6d9c79126440364c69f4e40c94b" content-hash = "1ff81969f837d57f7f28e6acdba690cde00aeedef64516953504c6f816ac73dd"
[metadata.files] [metadata.files]
aiodns = [ aiodns = [
@ -324,6 +335,10 @@ flake8 = [
{file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"},
{file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"},
] ]
humanize = [
{file = "humanize-3.2.0-py3-none-any.whl", hash = "sha256:d47d80cd47c1511ed3e49ca5f10c82ed940ea020b45b49ab106ed77fa8bb9d22"},
{file = "humanize-3.2.0.tar.gz", hash = "sha256:ab69004895689951b79f2ae4fdd6b8127ff0c180aff107856d5d98119a33f026"},
]
importlib-metadata = [ importlib-metadata = [
{file = "importlib_metadata-3.3.0-py3-none-any.whl", hash = "sha256:bf792d480abbd5eda85794e4afb09dd538393f7d6e6ffef6e9f03d2014cf9450"}, {file = "importlib_metadata-3.3.0-py3-none-any.whl", hash = "sha256:bf792d480abbd5eda85794e4afb09dd538393f7d6e6ffef6e9f03d2014cf9450"},
{file = "importlib_metadata-3.3.0.tar.gz", hash = "sha256:5c5a2720817414a6c41f0a49993908068243ae02c1635a228126519b509c8aed"}, {file = "importlib_metadata-3.3.0.tar.gz", hash = "sha256:5c5a2720817414a6c41f0a49993908068243ae02c1635a228126519b509c8aed"},

View File

@ -16,6 +16,7 @@ keywords = []
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.6" python = "^3.6"
slixmpp = "^1.6.0" slixmpp = "^1.6.0"
humanize = "^3.2.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
black = "^19.10b0" black = "^19.10b0"

View File

@ -2,6 +2,7 @@
from argparse import ArgumentParser from argparse import ArgumentParser
from configparser import ConfigParser from configparser import ConfigParser
from datetime import datetime as dt
from getpass import getpass from getpass import getpass
from logging import DEBUG, INFO, basicConfig, getLogger from logging import DEBUG, INFO, basicConfig, getLogger
from os import environ from os import environ
@ -9,6 +10,7 @@ from os.path import exists
from pathlib import Path from pathlib import Path
from sys import exit, stdout from sys import exit, stdout
from humanize import naturaldelta
from slixmpp import ClientXMPP from slixmpp import ClientXMPP
@ -69,6 +71,8 @@ class Bot(ClientXMPP):
def __init__(self): def __init__(self):
self.name = type(self).__name__.lower() self.name = type(self).__name__.lower()
self.start = dt.now()
self.CONFIG_FILE = f"{self.name}.conf" self.CONFIG_FILE = f"{self.name}.conf"
self.parse_arguments() self.parse_arguments()
@ -191,8 +195,14 @@ class Bot(ClientXMPP):
def direct_message(self, message): def direct_message(self, message):
"""Handle message event.""" """Handle message event."""
if message["type"] in ("chat", "normal"): if message["type"] in ("chat", "normal"):
_message = SimpleMessage(message)
if _message.body.startswith("!"):
self.command(_message, to=_message.sender)
return
try: try:
self.direct(SimpleMessage(message)) self.direct(_message)
except AttributeError: except AttributeError:
self.log.info("Bot.direct not implemented") self.log.info("Bot.direct not implemented")
@ -209,8 +219,14 @@ class Bot(ClientXMPP):
"""Handle groupchat_message event.""" """Handle groupchat_message event."""
if message["type"] in ("groupchat", "normal"): if message["type"] in ("groupchat", "normal"):
if message["mucnick"] != self.config.nick: if message["mucnick"] != self.config.nick:
_message = SimpleMessage(message)
if f"{self.nick}:!" in _message.body:
self.command(_message, room=_message.room)
return
try: try:
self.group(SimpleMessage(message)) self.group(_message)
except AttributeError: except AttributeError:
self.log.info("Bot.group not implemented") self.log.info("Bot.group not implemented")
@ -249,6 +265,25 @@ class Bot(ClientXMPP):
self.send_message(**kwargs) self.send_message(**kwargs)
@property
def uptime(self):
"""Time since the bot came up."""
return naturaldelta(self.start - dt.now())
def command(self, message, **kwargs):
"""Handle "!" style commands with built-in responses."""
command = message.body.split("!")[-1]
if command == "uptime":
self.reply(self.uptime, **kwargs)
elif command == "help":
try:
self.reply(self.help, **kwargs)
except AttributeError:
self.reply("No help found 🤔️", **kwargs)
else:
self.log.error(f"'{command}' direct command is not recognised")
class EchoBot(Bot): class EchoBot(Bot):
"""Responds with whatever you send. """Responds with whatever you send.
@ -261,6 +296,8 @@ class EchoBot(Bot):
""" """
help = "I echo back whatever you send to me 🖖️"
def direct(self, message): def direct(self, message):
"""Send back whatever we receive.""" """Send back whatever we receive."""
self.reply(message.body, to=message.sender) self.reply(message.body, to=message.sender)
@ -282,6 +319,8 @@ class WhisperBot(Bot):
""" """
help = "I whisper your private messages into group chats 😌️"
def direct(self, message): def direct(self, message):
"""Receive private messages and whisper them into group chats.""" """Receive private messages and whisper them into group chats."""
self.reply(f"*pssttt...* {message.body}", room=message.room) self.reply(f"*pssttt...* {message.body}", room=message.room)