Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ee5f4cb1b | |||
| 7471da08ce | |||
| b8f456d108 | |||
| 9a5b6fef60 | |||
| 904b9cb9fd | |||
| 951c509fc9 | |||
| 69fec3514f | |||
| ace8c2b27e | |||
| 3b2471bb4b | |||
| 78e0de08e5 |
@@ -4,7 +4,27 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# Advanced Community Bot
|
<h1 align="center">
|
||||||
|
Advanced Community Bot
|
||||||
|
</span>
|
||||||
|
<h4 align="center">
|
||||||
|
<span style="display:inline-flex; align-items:center; gap:12px;">
|
||||||
|
Advanced Community Bot is a Maubot Bot Plugin to manage Matrix servers.
|
||||||
|
</span>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
<h6 align="center">
|
||||||
|
<a href="https://ztfr.eu">🏰 Website</a>
|
||||||
|
·
|
||||||
|
<a href="https://ztfr.eu/matrix">📰 Zeitfresser Matrix Community</a>
|
||||||
|
·
|
||||||
|
<a href="https://social.ztfr.eu/@dome">🐘 Mastodon</a>
|
||||||
|
·
|
||||||
|
<a href="https://look.ztfr.eu/#/#support:ztfr.eu">💬 Supportchat</a>
|
||||||
|
</h6>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## ✨ Introduction
|
||||||
|
|
||||||
Advanced Community Bot is a powerful Maubot plugin designed to help you manage Matrix communities that are structured around Spaces. It combines moderation tools, automation, and community-driven workflows into a single, opinionated solution that focuses on simplicity, reliability, and clean integration with modern Matrix clients.
|
Advanced Community Bot is a powerful Maubot plugin designed to help you manage Matrix communities that are structured around Spaces. It combines moderation tools, automation, and community-driven workflows into a single, opinionated solution that focuses on simplicity, reliability, and clean integration with modern Matrix clients.
|
||||||
|
|
||||||
@@ -12,8 +32,6 @@ The plugin is particularly well suited for communities that want strong control
|
|||||||
|
|
||||||
It was originally created as Community Bot by <a href="https://github.com/williamkray/maubot-communitybot">William Kray</a>. This fork uses his bases and adds additional features and refinments to the bot.
|
It was originally created as Community Bot by <a href="https://github.com/williamkray/maubot-communitybot">William Kray</a>. This fork uses his bases and adds additional features and refinments to the bot.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🛠 What this bot is for
|
## 🛠 What this bot is for
|
||||||
|
|
||||||
Advanced Community Bot is not meant to replace large-scale moderation frameworks like Draupnir or Mjolnir. Instead, it focuses on providing a cohesive set of tools for managing structured communities with minimal overhead.
|
Advanced Community Bot is not meant to replace large-scale moderation frameworks like Draupnir or Mjolnir. Instead, it focuses on providing a cohesive set of tools for managing structured communities with minimal overhead.
|
||||||
@@ -154,6 +172,10 @@ Install the plugin like any other Maubot plugin:
|
|||||||
|
|
||||||
Make sure the bot has sufficient permissions in your rooms (especially for kicking, banning, and redacting messages), otherwise some features will not function correctly.
|
Make sure the bot has sufficient permissions in your rooms (especially for kicking, banning, and redacting messages), otherwise some features will not function correctly.
|
||||||
|
|
||||||
|
## 🛠 Development & Support
|
||||||
|
|
||||||
|
If you need to get support or want to participate in the active development of this software, you can <a href="https://ztfr.eu/matrix">join our Zeitfresser Matrix Community</a> or the <a href="https://look.ztfr.eu/#/#support:ztfr.eu">Development & Support Channel</a> on Matrix.
|
||||||
|
|
||||||
## 🧭 Final Notes
|
## 🧭 Final Notes
|
||||||
|
|
||||||
Advanced Community Bot aims to strike a balance between usability and control. It provides the tools needed to manage a structured Matrix community effectively, without overwhelming administrators with complexity.
|
Advanced Community Bot aims to strike a balance between usability and control. It provides the tools needed to manage a structured Matrix community effectively, without overwhelming administrators with complexity.
|
||||||
|
|||||||
+10
-1
@@ -91,7 +91,7 @@ welcome_sleep: 0
|
|||||||
# (optional)
|
# (optional)
|
||||||
notification_room:
|
notification_room:
|
||||||
|
|
||||||
# message to send to the notification room when someone joins one of the above rooms:
|
# message to send to the notification room when someone joins or leave one of the above rooms:
|
||||||
# available placeholders:
|
# available placeholders:
|
||||||
# - {user}: display name of the joining user (falls back to localpart or user ID)
|
# - {user}: display name of the joining user (falls back to localpart or user ID)
|
||||||
# - {user_id}: full Matrix user ID
|
# - {user_id}: full Matrix user ID
|
||||||
@@ -101,6 +101,15 @@ notification_room:
|
|||||||
# - {room_id}: raw room ID
|
# - {room_id}: raw room ID
|
||||||
join_notification_message: |
|
join_notification_message: |
|
||||||
{user} has joined {room}.
|
{user} has joined {room}.
|
||||||
|
|
||||||
|
leave_notification_message: |
|
||||||
|
{user} has left {room}.
|
||||||
|
|
||||||
|
kick_notification_message: |
|
||||||
|
{user} was kicked by {actor} from {room}.
|
||||||
|
|
||||||
|
ban_notification_message: |
|
||||||
|
{user} was baned by {actor} from {room}.
|
||||||
|
|
||||||
# whether to censor files/messages
|
# whether to censor files/messages
|
||||||
# can be boolean (true/false) for all-or-nothing behavior,
|
# can be boolean (true/false) for all-or-nothing behavior,
|
||||||
|
|||||||
+79
-1
@@ -206,6 +206,8 @@ class CommunityBot(Plugin):
|
|||||||
target_room_id: RoomID,
|
target_room_id: RoomID,
|
||||||
template: str,
|
template: str,
|
||||||
context: RenderContext,
|
context: RenderContext,
|
||||||
|
actor_id: Optional[str] = None,
|
||||||
|
actor_display: Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Render a template once and send plaintext + HTML variants."""
|
"""Render a template once and send plaintext + HTML variants."""
|
||||||
plain_text, html_message = self._render_message_template(
|
plain_text, html_message = self._render_message_template(
|
||||||
@@ -214,6 +216,8 @@ class CommunityBot(Plugin):
|
|||||||
context.user_display,
|
context.user_display,
|
||||||
context.room_id,
|
context.room_id,
|
||||||
context.room_text,
|
context.room_text,
|
||||||
|
actor_id,
|
||||||
|
actor_display,
|
||||||
)
|
)
|
||||||
await self.client.send_notice(target_room_id, plain_text, html=html_message)
|
await self.client.send_notice(target_room_id, plain_text, html=html_message)
|
||||||
|
|
||||||
@@ -237,6 +241,56 @@ class CommunityBot(Plugin):
|
|||||||
self.config["join_notification_message"],
|
self.config["join_notification_message"],
|
||||||
context,
|
context,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def _handle_leave_notifications(self, evt: StateEvent, event_type: str) -> None:
|
||||||
|
"""Send notifications when a user leaves, is kicked, or banned."""
|
||||||
|
|
||||||
|
# Optional: nur relevante Räume (wie bei join)
|
||||||
|
space_rooms = await self.get_space_roomlist()
|
||||||
|
if evt.room_id not in space_rooms:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.config["notification_room"]:
|
||||||
|
return
|
||||||
|
|
||||||
|
user_id = evt.state_key
|
||||||
|
sender = evt.sender
|
||||||
|
|
||||||
|
context = await self._build_render_context(evt.room_id, user_id)
|
||||||
|
|
||||||
|
# === Actor bestimmen ===
|
||||||
|
actor_id = None
|
||||||
|
actor_display = None
|
||||||
|
|
||||||
|
if sender != user_id:
|
||||||
|
actor_id = sender
|
||||||
|
actor_display = await self._get_user_display_name(evt.room_id, sender)
|
||||||
|
|
||||||
|
# === Event-Typ bestimmen ===
|
||||||
|
if event_type == "leave" and sender == user_id:
|
||||||
|
template = self.config["leave_notification_message"]
|
||||||
|
|
||||||
|
elif event_type == "kick":
|
||||||
|
template = self.config["kick_notification_message"]
|
||||||
|
|
||||||
|
elif event_type == "ban":
|
||||||
|
template = self.config["ban_notification_message"]
|
||||||
|
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
# === Template cleanup wenn kein actor ===
|
||||||
|
if not actor_id:
|
||||||
|
template = template.replace(" von {actor}", "")
|
||||||
|
template = template.replace(" {actor}", "")
|
||||||
|
|
||||||
|
await self._send_rendered_notice(
|
||||||
|
self.config["notification_room"],
|
||||||
|
template,
|
||||||
|
context,
|
||||||
|
actor_id=actor_id,
|
||||||
|
actor_display=actor_display,
|
||||||
|
)
|
||||||
|
|
||||||
def _is_human_verification_enabled_for_room(self, room_id: RoomID) -> bool:
|
def _is_human_verification_enabled_for_room(self, room_id: RoomID) -> bool:
|
||||||
configured = self.config["check_if_human"]
|
configured = self.config["check_if_human"]
|
||||||
@@ -407,6 +461,20 @@ class CommunityBot(Plugin):
|
|||||||
href = self._matrix_uri_user(str(user_id))
|
href = self._matrix_uri_user(str(user_id))
|
||||||
|
|
||||||
return label, f"<a href='{href}'>{escape(label)}</a>"
|
return label, f"<a href='{href}'>{escape(label)}</a>"
|
||||||
|
|
||||||
|
def _format_actor_pill(
|
||||||
|
self,
|
||||||
|
actor_id: Optional[str],
|
||||||
|
actor_display: Optional[str] = None,
|
||||||
|
) -> Tuple[str, str]:
|
||||||
|
"""Return plaintext and HTML variants for the {actor} placeholder."""
|
||||||
|
if not actor_id:
|
||||||
|
return "", ""
|
||||||
|
|
||||||
|
safe_display = actor_display or actor_id
|
||||||
|
href = self._matrix_uri_user(str(actor_id))
|
||||||
|
|
||||||
|
return safe_display, f"<a href='{href}'>{escape(safe_display)}</a>"
|
||||||
|
|
||||||
def _format_room_pill(
|
def _format_room_pill(
|
||||||
self,
|
self,
|
||||||
@@ -434,6 +502,8 @@ class CommunityBot(Plugin):
|
|||||||
user_display: Optional[str] = None,
|
user_display: Optional[str] = None,
|
||||||
room_id: Optional[str] = None,
|
room_id: Optional[str] = None,
|
||||||
room_text: Optional[str] = None,
|
room_text: Optional[str] = None,
|
||||||
|
actor_id: Optional[str] = None,
|
||||||
|
actor_display: Optional[str] = None,
|
||||||
) -> Tuple[str, str]:
|
) -> Tuple[str, str]:
|
||||||
user_url = self._matrix_to_url(user_id)
|
user_url = self._matrix_to_url(user_id)
|
||||||
safe_user_display = user_display or user_id
|
safe_user_display = user_display or user_id
|
||||||
@@ -442,6 +512,7 @@ class CommunityBot(Plugin):
|
|||||||
room_url = self._matrix_to_url(safe_room_id) if safe_room_id else ""
|
room_url = self._matrix_to_url(safe_room_id) if safe_room_id else ""
|
||||||
user_plain, user_html = self._format_user_pill(user_id, safe_user_display)
|
user_plain, user_html = self._format_user_pill(user_id, safe_user_display)
|
||||||
room_plain, room_html = self._format_room_pill(safe_room_id, safe_room_text)
|
room_plain, room_html = self._format_room_pill(safe_room_id, safe_room_text)
|
||||||
|
actor_plain, actor_html = self._format_actor_pill(actor_id, actor_display)
|
||||||
|
|
||||||
plain_text = template.format(
|
plain_text = template.format(
|
||||||
user=user_plain,
|
user=user_plain,
|
||||||
@@ -450,6 +521,8 @@ class CommunityBot(Plugin):
|
|||||||
room=room_plain,
|
room=room_plain,
|
||||||
room_link=room_url,
|
room_link=room_url,
|
||||||
room_id=safe_room_id,
|
room_id=safe_room_id,
|
||||||
|
actor=actor_plain,
|
||||||
|
actor_display=actor_display or "",
|
||||||
)
|
)
|
||||||
|
|
||||||
html_message = template.format(
|
html_message = template.format(
|
||||||
@@ -462,7 +535,9 @@ class CommunityBot(Plugin):
|
|||||||
if room_url
|
if room_url
|
||||||
else escape(safe_room_text)
|
else escape(safe_room_text)
|
||||||
),
|
),
|
||||||
room_id=escape(safe_room_id),
|
room_id=safe_room_id,
|
||||||
|
actor=actor_html,
|
||||||
|
actor_display=escape(actor_display) if actor_display else "",
|
||||||
)
|
)
|
||||||
|
|
||||||
return plain_text, html_message
|
return plain_text, html_message
|
||||||
@@ -1331,16 +1406,19 @@ class CommunityBot(Plugin):
|
|||||||
async def handle_leave(self, evt: StateEvent) -> None:
|
async def handle_leave(self, evt: StateEvent) -> None:
|
||||||
"""Handle voluntary leave events."""
|
"""Handle voluntary leave events."""
|
||||||
await self.handle_leave_events(evt)
|
await self.handle_leave_events(evt)
|
||||||
|
await self._handle_leave_notifications(evt, "leave")
|
||||||
|
|
||||||
@event.on(InternalEventType.KICK)
|
@event.on(InternalEventType.KICK)
|
||||||
async def handle_kick(self, evt: StateEvent) -> None:
|
async def handle_kick(self, evt: StateEvent) -> None:
|
||||||
"""Handle kick events."""
|
"""Handle kick events."""
|
||||||
await self.handle_leave_events(evt)
|
await self.handle_leave_events(evt)
|
||||||
|
await self._handle_leave_notifications(evt, "kick")
|
||||||
|
|
||||||
@event.on(InternalEventType.BAN)
|
@event.on(InternalEventType.BAN)
|
||||||
async def handle_ban(self, evt: StateEvent) -> None:
|
async def handle_ban(self, evt: StateEvent) -> None:
|
||||||
"""Handle ban events."""
|
"""Handle ban events."""
|
||||||
await self.handle_leave_events(evt)
|
await self.handle_leave_events(evt)
|
||||||
|
await self._handle_leave_notifications(evt, "ban")
|
||||||
|
|
||||||
@event.on(InternalEventType.JOIN)
|
@event.on(InternalEventType.JOIN)
|
||||||
async def newjoin(self, evt: StateEvent) -> None:
|
async def newjoin(self, evt: StateEvent) -> None:
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ maubot: 0.1.0
|
|||||||
id: advanced-community-bot
|
id: advanced-community-bot
|
||||||
name: Advanced Community Bot
|
name: Advanced Community Bot
|
||||||
description: Advanced Community Bot is a Maubot Bot Plugin to manage Matrix servers.
|
description: Advanced Community Bot is a Maubot Bot Plugin to manage Matrix servers.
|
||||||
version: 1.0.0
|
version: 1.0.1
|
||||||
license: MIT
|
license: MIT
|
||||||
|
|
||||||
modules:
|
modules:
|
||||||
|
|||||||
Reference in New Issue
Block a user