slck/main.py

98 lines
2.5 KiB
Python
Raw Normal View History

"""
slck: Slack Status CLI
Facilitates setting Slack status text/emojis via the
command-line.
"""
import pathlib
import click
import pydantic
import slack_sdk
import yaml
class ProfilePayload(pydantic.BaseModel):
"""Profile payload sent to Slack's API."""
status_text: str = ""
status_emoji: str = ""
status_expiration: int = 0
class Preset(pydantic.BaseModel):
"""Represents a set of value used as a preset."""
text: str
emoji: str = ""
class Configuration(pydantic.BaseModel):
"""Tool configuration."""
token: str
presets: dict[str, Preset]
def get_client(token: str) -> slack_sdk.WebClient:
"""Returns an authenticated API client."""
return slack_sdk.WebClient(token=token)
def get_configuration(path: str) -> Configuration:
"""Loads configuration from file."""
conf_path = pathlib.Path(path)
if not conf_path.exists():
raise RuntimeError(f"Configuration file not found: {path}")
with open(conf_path, "r", encoding="utf8") as conf_file:
return Configuration(**yaml.safe_load(conf_file))
@click.command()
@click.option("--text", "-t", help="Status text.")
@click.option("--emoji", "-e", help="Emoji attached to the status.")
@click.option("--preset", "-p", help="Preset for text/emoji combinations.")
@click.option("--config", "-c", "config_path", help="Path to configuration.")
def cli(
*, text: str = None, emoji: str = None, preset: str = None, config_path: str = None
):
if text is None and preset is None:
raise RuntimeError(
"Must specify either status text via --text/-t or a preset via --preset/-p."
)
conf = get_configuration(config_path)
status_text, status_emoji = None, None
if preset is not None and preset in conf.presets:
preset_data = conf.presets[preset]
status_text = preset_data.text if preset_data.text else status_text
status_emoji = preset_data.emoji if preset_data.emoji else status_emoji
elif preset is not None:
raise RuntimeError(f"Unknown preset: {preset}")
if text is not None:
status_text = text
if emoji is not None:
status_emoji = emoji
payload = ProfilePayload(status_text=status_text, status_emoji=status_emoji)
client = get_client(conf.token)
api_response = client.users_profile_set(profile=payload.model_dump())
if not api_response.get("ok", False):
raise RuntimeError("Failed to set status!")
def run():
"""Entrypoint."""
try:
cli()
except Exception as e:
click.echo(e)