Initial commit - Excommunicado Discord bot (XCOM stealth isolation)
This commit is contained in:
+102
@@ -0,0 +1,102 @@
|
||||
"""Configuration and persistence for the Excommunicado bot."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
DATA_DIR = Path(__file__).parent.parent / "data"
|
||||
CONFIG_FILE = DATA_DIR / "xcom_config.json"
|
||||
|
||||
|
||||
def _ensure_data_dir() -> None:
|
||||
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def load_config() -> Dict[str, Any]:
|
||||
"""Load the entire config dict."""
|
||||
_ensure_data_dir()
|
||||
if not CONFIG_FILE.exists():
|
||||
save_config({})
|
||||
return {}
|
||||
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def save_config(data: Dict[str, Any]) -> None:
|
||||
"""Save the config dict."""
|
||||
_ensure_data_dir()
|
||||
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
def get_guild_data(guild_id: int) -> Dict[str, Any]:
|
||||
"""Get or initialize data for a specific guild."""
|
||||
config = load_config()
|
||||
gid = str(guild_id)
|
||||
if gid not in config:
|
||||
config[gid] = {
|
||||
"xcom_role_id": None,
|
||||
"xcom_channel_id": None,
|
||||
"isolated_users": {} # user_id -> {"reason": str, "timestamp": str}
|
||||
}
|
||||
save_config(config)
|
||||
return config[gid]
|
||||
|
||||
|
||||
def update_guild_data(guild_id: int, key: str, value: Any) -> None:
|
||||
"""Update a top-level key for the guild."""
|
||||
config = load_config()
|
||||
gid = str(guild_id)
|
||||
if gid not in config:
|
||||
config[gid] = {
|
||||
"xcom_role_id": None,
|
||||
"xcom_channel_id": None,
|
||||
"isolated_users": {}
|
||||
}
|
||||
config[gid][key] = value
|
||||
save_config(config)
|
||||
|
||||
|
||||
def add_isolated_user(guild_id: int, user_id: int, reason: str, timestamp: str) -> None:
|
||||
"""Record a newly isolated user (shared xcom-lounge channel)."""
|
||||
config = load_config()
|
||||
gid = str(guild_id)
|
||||
if gid not in config:
|
||||
config[gid] = {"xcom_role_id": None, "xcom_channel_id": None, "isolated_users": {}}
|
||||
config[gid]["isolated_users"][str(user_id)] = {
|
||||
"reason": reason,
|
||||
"timestamp": timestamp,
|
||||
"absolution_points": 0,
|
||||
"marked": True
|
||||
}
|
||||
save_config(config)
|
||||
|
||||
|
||||
def increment_absolution_points(guild_id: int, user_id: int, amount: int = 1) -> int:
|
||||
"""Increase absolution points for a user and return the new total."""
|
||||
config = load_config()
|
||||
gid = str(guild_id)
|
||||
uid = str(user_id)
|
||||
if gid in config and uid in config[gid].get("isolated_users", {}):
|
||||
current = config[gid]["isolated_users"][uid].get("absolution_points", 0)
|
||||
new_total = current + amount
|
||||
config[gid]["isolated_users"][uid]["absolution_points"] = new_total
|
||||
save_config(config)
|
||||
return new_total
|
||||
return 0
|
||||
|
||||
|
||||
def remove_isolated_user(guild_id: int, user_id: int) -> Optional[Dict]:
|
||||
"""Remove user from isolation record and return previous data or None."""
|
||||
config = load_config()
|
||||
gid = str(guild_id)
|
||||
if gid in config and str(user_id) in config[gid].get("isolated_users", {}):
|
||||
data = config[gid]["isolated_users"].pop(str(user_id))
|
||||
save_config(config)
|
||||
return data
|
||||
return None
|
||||
|
||||
|
||||
def get_isolated_users(guild_id: int) -> Dict[str, Dict]:
|
||||
"""Return all isolated users for guild."""
|
||||
data = get_guild_data(guild_id)
|
||||
return data.get("isolated_users", {})
|
||||
Reference in New Issue
Block a user