Initial commit
This commit is contained in:
306
modules/admin/__init__.py
Normal file
306
modules/admin/__init__.py
Normal file
@@ -0,0 +1,306 @@
|
||||
from core.module import Module
|
||||
|
||||
|
||||
class AdminModule(Module):
|
||||
name = "admin"
|
||||
version = "0.1.0"
|
||||
description = "Admin commands"
|
||||
|
||||
async def on_load(self) -> None:
|
||||
builder = self.commands
|
||||
await self.app.database.execute(
|
||||
"CREATE TABLE IF NOT EXISTS admin_welcome (chat_id INTEGER PRIMARY KEY, message TEXT)"
|
||||
)
|
||||
await self.app.database.execute(
|
||||
"CREATE TABLE IF NOT EXISTS admin_stats (chat_id INTEGER PRIMARY KEY, messages INTEGER)"
|
||||
)
|
||||
|
||||
async def on_message(evt):
|
||||
event = evt.payload.get("event")
|
||||
chat_id = getattr(event, "chat_id", None)
|
||||
if not chat_id:
|
||||
return
|
||||
row = await self.app.database.fetchone(
|
||||
"SELECT messages FROM admin_stats WHERE chat_id=?",
|
||||
(chat_id,),
|
||||
)
|
||||
count = (row["messages"] if row else 0) + 1
|
||||
await self.app.database.execute(
|
||||
"INSERT OR REPLACE INTO admin_stats (chat_id, messages) VALUES (?, ?)",
|
||||
(chat_id, count),
|
||||
)
|
||||
|
||||
async def on_chat(evt):
|
||||
event = evt.payload.get("event")
|
||||
if not getattr(event, "user_joined", False) and not getattr(event, "user_added", False):
|
||||
return
|
||||
chat_id = getattr(event, "chat_id", None)
|
||||
if not chat_id:
|
||||
return
|
||||
row = await self.app.database.fetchone(
|
||||
"SELECT message FROM admin_welcome WHERE chat_id=?",
|
||||
(chat_id,),
|
||||
)
|
||||
if row:
|
||||
await event.client.send_message(chat_id, row["message"])
|
||||
|
||||
self.app.events.on("on_message_new", on_message)
|
||||
self.app.events.on("on_chat_action", on_chat)
|
||||
|
||||
@builder.command(
|
||||
name="pin",
|
||||
description="Stub pin command",
|
||||
category="admin",
|
||||
usage=".pin",
|
||||
)
|
||||
async def pin_cmd(event, args):
|
||||
reply = await event.get_reply_message()
|
||||
if not reply:
|
||||
await event.reply("Reply to a message to pin")
|
||||
return
|
||||
await event.client.pin_message(event.chat_id, reply)
|
||||
await event.reply("Pinned")
|
||||
|
||||
@builder.command(
|
||||
name="welcome",
|
||||
description="Stub welcome setup",
|
||||
category="admin",
|
||||
usage=".welcome <on|off>",
|
||||
)
|
||||
async def welcome_cmd(event, args):
|
||||
chat_id = getattr(event, "chat_id", None)
|
||||
if not chat_id:
|
||||
await event.reply("Chat only")
|
||||
return
|
||||
if not args:
|
||||
await event.reply("Usage: .welcome <on|off> [message]")
|
||||
return
|
||||
if args[0] == "on":
|
||||
message = " ".join(args[1:]) or "Welcome!"
|
||||
await self.app.database.execute(
|
||||
"INSERT OR REPLACE INTO admin_welcome (chat_id, message) VALUES (?, ?)",
|
||||
(chat_id, message),
|
||||
)
|
||||
await event.reply("Welcome enabled")
|
||||
return
|
||||
if args[0] == "off":
|
||||
await self.app.database.execute(
|
||||
"DELETE FROM admin_welcome WHERE chat_id=?",
|
||||
(chat_id,),
|
||||
)
|
||||
await event.reply("Welcome disabled")
|
||||
return
|
||||
await event.reply("Usage: .welcome <on|off> [message]")
|
||||
|
||||
@builder.command(
|
||||
name="stats",
|
||||
description="Stub group stats",
|
||||
category="admin",
|
||||
usage=".stats",
|
||||
)
|
||||
async def stats_cmd(event, args):
|
||||
chat_id = getattr(event, "chat_id", None)
|
||||
if not chat_id:
|
||||
await event.reply("Chat only")
|
||||
return
|
||||
row = await self.app.database.fetchone(
|
||||
"SELECT messages FROM admin_stats WHERE chat_id=?",
|
||||
(chat_id,),
|
||||
)
|
||||
await event.reply(f"Messages: {row['messages'] if row else 0}")
|
||||
|
||||
@builder.command(
|
||||
name="modules",
|
||||
description="Manage modules",
|
||||
category="admin",
|
||||
usage=".modules <list|enable|disable|reload|info|config|update> [name]",
|
||||
example=".modules list",
|
||||
permission="admin",
|
||||
)
|
||||
async def modules_cmd(event, args):
|
||||
if not args:
|
||||
await event.reply("Usage: .modules <list|enable|disable|reload|info|config|update> [name]")
|
||||
return
|
||||
action = args[0]
|
||||
name = args[1] if len(args) > 1 else None
|
||||
module_config = self.app.config.get_modules().setdefault("modules", {})
|
||||
if action == "update":
|
||||
sub = args[1] if len(args) > 1 else "check"
|
||||
if sub == "check":
|
||||
try:
|
||||
commits = await self.app.module_updates.check_updates()
|
||||
except Exception as exc:
|
||||
await event.reply(f"Update check failed: {exc}")
|
||||
return
|
||||
await event.reply("\n".join(commits) if commits else "No module updates")
|
||||
return
|
||||
if sub == "list":
|
||||
try:
|
||||
commits = await self.app.module_updates.check_updates()
|
||||
except Exception as exc:
|
||||
await event.reply(f"Update list failed: {exc}")
|
||||
return
|
||||
await event.reply("\n".join(commits) if commits else "No module updates")
|
||||
return
|
||||
if sub == "all":
|
||||
try:
|
||||
output = await self.app.module_updates.update_all()
|
||||
except Exception as exc:
|
||||
self.app.update_service.record_event(
|
||||
action="module_update",
|
||||
status="failed",
|
||||
meta={"module": "all"},
|
||||
)
|
||||
await event.reply(f"Update failed: {exc}")
|
||||
return
|
||||
self.app.update_service.record_event(
|
||||
action="module_update",
|
||||
status="success",
|
||||
meta={"module": "all"},
|
||||
)
|
||||
await event.reply(output or "Modules updated")
|
||||
return
|
||||
if sub not in {"rollback"}:
|
||||
try:
|
||||
output = await self.app.module_updates.update_all()
|
||||
except Exception as exc:
|
||||
self.app.update_service.record_event(
|
||||
action="module_update",
|
||||
status="failed",
|
||||
meta={"module": sub},
|
||||
)
|
||||
await event.reply(f"Update failed: {exc}")
|
||||
return
|
||||
await self.app.modules.reload(f"modules.{sub}")
|
||||
self.app.update_service.record_event(
|
||||
action="module_update",
|
||||
status="success",
|
||||
meta={"module": sub},
|
||||
)
|
||||
await event.reply(f"Updated {sub}")
|
||||
return
|
||||
if sub == "rollback":
|
||||
ref = args[2] if len(args) > 2 else "HEAD~1"
|
||||
try:
|
||||
output = await self.app.module_updates.rollback(ref)
|
||||
except Exception as exc:
|
||||
self.app.update_service.record_event(
|
||||
action="module_rollback",
|
||||
status="failed",
|
||||
meta={"ref": ref},
|
||||
)
|
||||
await event.reply(f"Rollback failed: {exc}")
|
||||
return
|
||||
self.app.update_service.record_event(
|
||||
action="module_rollback",
|
||||
status="success",
|
||||
meta={"ref": ref},
|
||||
)
|
||||
await event.reply(output or "Rolled back")
|
||||
return
|
||||
await event.reply("Usage: .modules update <check|all|rollback> [ref]")
|
||||
return
|
||||
if action == "list":
|
||||
loaded = set(self.app.modules.list())
|
||||
summary = []
|
||||
for mod_name, cfg in module_config.items():
|
||||
status = "loaded" if f"modules.{mod_name}" in loaded else "unloaded"
|
||||
enabled = "enabled" if cfg.get("enabled", True) else "disabled"
|
||||
summary.append(f"{mod_name} ({enabled}, {status})")
|
||||
await event.reply(", ".join(summary) if summary else "No modules configured")
|
||||
return
|
||||
if not name:
|
||||
await event.reply("Module name required")
|
||||
return
|
||||
module_path = f"modules.{name}"
|
||||
if action == "enable":
|
||||
module_config.setdefault(name, {})["enabled"] = True
|
||||
self.app.config.save_modules()
|
||||
await self.app.modules.load(module_path)
|
||||
await event.reply(f"Enabled {name}")
|
||||
return
|
||||
if action == "disable":
|
||||
module_config.setdefault(name, {})["enabled"] = False
|
||||
self.app.config.save_modules()
|
||||
await self.app.modules.unload(module_path)
|
||||
await event.reply(f"Disabled {name}")
|
||||
return
|
||||
if action == "reload":
|
||||
await self.app.modules.reload(module_path)
|
||||
await event.reply(f"Reloaded {name}")
|
||||
return
|
||||
if action == "info":
|
||||
cfg = module_config.get(name, {})
|
||||
loaded = module_path in self.app.modules.list()
|
||||
await event.reply(str({"name": name, "loaded": loaded, "config": cfg}))
|
||||
return
|
||||
if action == "config":
|
||||
cfg = module_config.get(name, {})
|
||||
await event.reply(str(cfg))
|
||||
return
|
||||
await event.reply("Unknown action")
|
||||
|
||||
@builder.command(
|
||||
name="backup",
|
||||
description="Manage backups",
|
||||
category="admin",
|
||||
usage=".backup <create|list|delete> <core|modules|plugins> [name]",
|
||||
permission="admin",
|
||||
)
|
||||
async def backup_cmd(event, args):
|
||||
if not args:
|
||||
await event.reply("Usage: .backup <create|list|delete|auto|schedule> <core|modules|plugins> [name]")
|
||||
return
|
||||
action = args[0]
|
||||
manager = self.app.backups
|
||||
if action in {"auto", "schedule"}:
|
||||
if action == "auto":
|
||||
toggle = args[1] if len(args) > 1 else "on"
|
||||
cfg = self.app.config.get().setdefault("backup", {})
|
||||
cfg["auto"] = toggle == "on"
|
||||
self.app.config.save()
|
||||
await event.reply(f"Auto-backup {'enabled' if cfg['auto'] else 'disabled'}")
|
||||
return
|
||||
if action == "schedule":
|
||||
if len(args) < 2:
|
||||
await event.reply("Time required")
|
||||
return
|
||||
cfg = self.app.config.get().setdefault("backup", {})
|
||||
cfg["schedule"] = args[1]
|
||||
self.app.config.save()
|
||||
await event.reply("Backup schedule updated")
|
||||
return
|
||||
if len(args) < 2:
|
||||
await event.reply("Usage: .backup <create|list|delete|auto|schedule> <core|modules|plugins> [name]")
|
||||
return
|
||||
scope = args[1]
|
||||
if action == "create":
|
||||
try:
|
||||
path = manager.create(scope)
|
||||
except Exception as exc:
|
||||
self.app.update_service.record_event(
|
||||
action="backup",
|
||||
status="failed",
|
||||
meta={"scope": scope},
|
||||
)
|
||||
await event.reply(f"Backup failed: {exc}")
|
||||
return
|
||||
self.app.update_service.record_event(
|
||||
action="backup",
|
||||
status="success",
|
||||
meta={"scope": scope, "name": path.name},
|
||||
)
|
||||
await event.reply(f"Backup created: {path.name}")
|
||||
return
|
||||
if action == "list":
|
||||
items = manager.list(scope)
|
||||
await event.reply(", ".join(items) if items else "No backups found")
|
||||
return
|
||||
if action == "delete":
|
||||
if len(args) < 3:
|
||||
await event.reply("Backup name required")
|
||||
return
|
||||
manager.delete(scope, args[2])
|
||||
await event.reply("Backup deleted")
|
||||
return
|
||||
await event.reply("Unknown action")
|
||||
Reference in New Issue
Block a user