Add use_community_slug option to support disabling the slug suffix
This commit is contained in:
@@ -10,6 +10,10 @@ parent_room: ''
|
|||||||
# leave blank to generate an acronym of your community name during initialization
|
# leave blank to generate an acronym of your community name during initialization
|
||||||
community_slug: ''
|
community_slug: ''
|
||||||
|
|
||||||
|
# use_community_slug
|
||||||
|
# whether to use the community slug as a suffix for room aliases
|
||||||
|
use_community_slug: true
|
||||||
|
|
||||||
# sleep time between actions. you can drop this to 0 if your bot has no
|
# sleep time between actions. you can drop this to 0 if your bot has no
|
||||||
# ratelimits imposed on its homeserver, otherwise you may want to increase this
|
# ratelimits imposed on its homeserver, otherwise you may want to increase this
|
||||||
# to avoid errors.
|
# to avoid errors.
|
||||||
|
|||||||
+13
-5
@@ -70,6 +70,7 @@ class Config(BaseProxyConfig):
|
|||||||
helper.copy("welcome_sleep")
|
helper.copy("welcome_sleep")
|
||||||
helper.copy("parent_room")
|
helper.copy("parent_room")
|
||||||
helper.copy("community_slug")
|
helper.copy("community_slug")
|
||||||
|
helper.copy("use_community_slug")
|
||||||
helper.copy("track_users")
|
helper.copy("track_users")
|
||||||
helper.copy("warn_threshold_days")
|
helper.copy("warn_threshold_days")
|
||||||
helper.copy("kick_threshold_days")
|
helper.copy("kick_threshold_days")
|
||||||
@@ -174,7 +175,9 @@ class CommunityBot(Plugin):
|
|||||||
Returns:
|
Returns:
|
||||||
tuple: (is_valid, list_of_conflicting_aliases)
|
tuple: (is_valid, list_of_conflicting_aliases)
|
||||||
"""
|
"""
|
||||||
if not self.config.get("community_slug", ""):
|
if self.config.get("use_community_slug", True) and not self.config.get(
|
||||||
|
"community_slug", ""
|
||||||
|
):
|
||||||
if evt:
|
if evt:
|
||||||
await evt.respond(
|
await evt.respond(
|
||||||
"Error: No community slug configured. Please run initialize command first."
|
"Error: No community slug configured. Please run initialize command first."
|
||||||
@@ -183,7 +186,11 @@ class CommunityBot(Plugin):
|
|||||||
|
|
||||||
server = self.client.parse_user_id(self.client.mxid)[1]
|
server = self.client.parse_user_id(self.client.mxid)[1]
|
||||||
return await room_utils.validate_room_aliases(
|
return await room_utils.validate_room_aliases(
|
||||||
self.client, room_names, self.config.get("community_slug", ""), server
|
self.client,
|
||||||
|
room_names,
|
||||||
|
self.config.get("community_slug", ""),
|
||||||
|
self.config.get("use_community_slug", True),
|
||||||
|
server,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_moderators_and_above(self) -> list[str]:
|
async def get_moderators_and_above(self) -> list[str]:
|
||||||
@@ -1849,7 +1856,7 @@ class CommunityBot(Plugin):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Check if community slug is configured
|
# Check if community slug is configured
|
||||||
if not self.config["community_slug"]:
|
if self.config["use_community_slug"] and not self.config["community_slug"]:
|
||||||
await evt.reply(
|
await evt.reply(
|
||||||
"No community slug configured. Please run initialize command first."
|
"No community slug configured. Please run initialize command first."
|
||||||
)
|
)
|
||||||
@@ -2055,7 +2062,7 @@ class CommunityBot(Plugin):
|
|||||||
aliases_to_transfer = await self.remove_room_aliases(room_id, evt)
|
aliases_to_transfer = await self.remove_room_aliases(room_id, evt)
|
||||||
|
|
||||||
# Check if community slug is configured
|
# Check if community slug is configured
|
||||||
if not self.config["community_slug"]:
|
if self.config["use_community_slug"] and not self.config["community_slug"]:
|
||||||
await evt.respond(
|
await evt.respond(
|
||||||
"No community slug configured. Please run initialize command first."
|
"No community slug configured. Please run initialize command first."
|
||||||
)
|
)
|
||||||
@@ -2962,7 +2969,7 @@ class CommunityBot(Plugin):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Generate community slug if not already set
|
# Generate community slug if not already set
|
||||||
if not self.config["community_slug"]:
|
if self.config["use_community_slug"] and not self.config["community_slug"]:
|
||||||
community_slug = self.generate_community_slug(community_name)
|
community_slug = self.generate_community_slug(community_name)
|
||||||
self.config["community_slug"] = community_slug
|
self.config["community_slug"] = community_slug
|
||||||
self.log.info(f"Generated community slug: {community_slug}")
|
self.log.info(f"Generated community slug: {community_slug}")
|
||||||
@@ -3145,6 +3152,7 @@ class CommunityBot(Plugin):
|
|||||||
await evt.respond(
|
await evt.respond(
|
||||||
f"Community space initialized successfully!<br /><br />"
|
f"Community space initialized successfully!<br /><br />"
|
||||||
f"Community Slug: {self.config['community_slug']}<br />"
|
f"Community Slug: {self.config['community_slug']}<br />"
|
||||||
|
f"Use Community Slug: {self.config['use_community_slug']}"
|
||||||
f"Room Version: {self.config['room_version']}<br />"
|
f"Room Version: {self.config['room_version']}<br />"
|
||||||
f"Space: <a href='https://matrix.to/#/{space_alias}'>{space_alias}</a><br />"
|
f"Space: <a href='https://matrix.to/#/{space_alias}'>{space_alias}</a><br />"
|
||||||
f"Moderators Room: <a href='https://matrix.to/#/{mod_room_alias}'>{mod_room_alias}</a><br />"
|
f"Moderators Room: <a href='https://matrix.to/#/{mod_room_alias}'>{mod_room_alias}</a><br />"
|
||||||
|
|||||||
@@ -99,6 +99,14 @@ class ConfigManager:
|
|||||||
"""
|
"""
|
||||||
return self.config.get("community_slug")
|
return self.config.get("community_slug")
|
||||||
|
|
||||||
|
def get_use_community_slug(self) -> Optional[str]:
|
||||||
|
"""Get the community slug suffix setting.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: Whether to use the community slug as a room suffix
|
||||||
|
"""
|
||||||
|
return self.config.get("use_community_slug")
|
||||||
|
|
||||||
def get_parent_room(self) -> Optional[str]:
|
def get_parent_room(self) -> Optional[str]:
|
||||||
"""Get the parent room ID.
|
"""Get the parent room ID.
|
||||||
|
|
||||||
@@ -201,7 +209,12 @@ class ConfigManager:
|
|||||||
Returns:
|
Returns:
|
||||||
List[str]: List of missing required configuration keys
|
List[str]: List of missing required configuration keys
|
||||||
"""
|
"""
|
||||||
required_configs = ["parent_room", "room_version", "community_slug"]
|
required_configs = [
|
||||||
|
"parent_room",
|
||||||
|
"room_version",
|
||||||
|
"community_slug",
|
||||||
|
"use_community_slug",
|
||||||
|
]
|
||||||
|
|
||||||
missing = []
|
missing = []
|
||||||
for config_key in required_configs:
|
for config_key in required_configs:
|
||||||
@@ -231,6 +244,7 @@ class ConfigManager:
|
|||||||
return {
|
return {
|
||||||
"room_version": self.get_room_version(),
|
"room_version": self.get_room_version(),
|
||||||
"community_slug": self.get_community_slug(),
|
"community_slug": self.get_community_slug(),
|
||||||
|
"use_community_slug": self.get_use_community_slug(),
|
||||||
"invitees": self.get_invitees(),
|
"invitees": self.get_invitees(),
|
||||||
"invite_power_level": self.get_invite_power_level(),
|
"invite_power_level": self.get_invite_power_level(),
|
||||||
"encrypt": self.is_encryption_enabled(),
|
"encrypt": self.is_encryption_enabled(),
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ async def validate_room_creation_params(
|
|||||||
sanitized_name = re.sub(r"[^a-zA-Z0-9]", "", roomname).lower()
|
sanitized_name = re.sub(r"[^a-zA-Z0-9]", "", roomname).lower()
|
||||||
|
|
||||||
# Check if community slug is configured
|
# Check if community slug is configured
|
||||||
if not config.get("community_slug", ""):
|
if config.get("use_community_slug", True) and not config.get("community_slug", ""):
|
||||||
error_msg = "No community slug configured. Please run initialize command first."
|
error_msg = "No community slug configured. Please run initialize command first."
|
||||||
return sanitized_name, force_encryption, force_unencryption, error_msg, roomname
|
return sanitized_name, force_encryption, force_unencryption, error_msg, roomname
|
||||||
|
|
||||||
@@ -63,7 +63,10 @@ async def prepare_room_creation_data(
|
|||||||
Tuple of (alias_localpart, server, room_invitees, parent_room)
|
Tuple of (alias_localpart, server, room_invitees, parent_room)
|
||||||
"""
|
"""
|
||||||
# Create alias with community slug
|
# Create alias with community slug
|
||||||
alias_localpart = f"{sanitized_name}-{config.get('community_slug', '')}"
|
if config.get("use_community_slug", True):
|
||||||
|
alias_localpart = f"{sanitized_name}-{config.get('community_slug', '')}"
|
||||||
|
else:
|
||||||
|
alias_localpart = sanitized_name
|
||||||
|
|
||||||
# Get server and invitees
|
# Get server and invitees
|
||||||
server = client.parse_user_id(client.mxid)[1]
|
server = client.parse_user_id(client.mxid)[1]
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ async def validate_room_alias(client, alias_localpart: str, server: str) -> bool
|
|||||||
|
|
||||||
|
|
||||||
async def validate_room_aliases(
|
async def validate_room_aliases(
|
||||||
client, room_names: list[str], community_slug: str, server: str
|
client,
|
||||||
|
room_names: list[str],
|
||||||
|
community_slug: str,
|
||||||
|
use_community_slug: bool,
|
||||||
|
server: str,
|
||||||
) -> Tuple[bool, List[str]]:
|
) -> Tuple[bool, List[str]]:
|
||||||
"""Validate that all room aliases are available.
|
"""Validate that all room aliases are available.
|
||||||
|
|
||||||
@@ -39,12 +43,13 @@ async def validate_room_aliases(
|
|||||||
client: Matrix client instance
|
client: Matrix client instance
|
||||||
room_names: List of room names to validate
|
room_names: List of room names to validate
|
||||||
community_slug: The community slug to append
|
community_slug: The community slug to append
|
||||||
|
use_community_slug: Whether to append a community slug
|
||||||
server: The server domain
|
server: The server domain
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple: (is_valid, list_of_conflicting_aliases)
|
tuple: (is_valid, list_of_conflicting_aliases)
|
||||||
"""
|
"""
|
||||||
if not community_slug:
|
if use_community_slug and not community_slug:
|
||||||
return False, []
|
return False, []
|
||||||
|
|
||||||
conflicting_aliases = []
|
conflicting_aliases = []
|
||||||
@@ -54,7 +59,10 @@ async def validate_room_aliases(
|
|||||||
from .message_utils import sanitize_room_name
|
from .message_utils import sanitize_room_name
|
||||||
|
|
||||||
sanitized_name = sanitize_room_name(room_name)
|
sanitized_name = sanitize_room_name(room_name)
|
||||||
alias_localpart = f"{sanitized_name}-{community_slug}"
|
if use_community_slug:
|
||||||
|
alias_localpart = f"{sanitized_name}-{community_slug}"
|
||||||
|
else:
|
||||||
|
alias_localpart = sanitized_name
|
||||||
|
|
||||||
# Check if alias is available
|
# Check if alias is available
|
||||||
is_available = await validate_room_alias(client, alias_localpart, server)
|
is_available = await validate_room_alias(client, alias_localpart, server)
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ plugin_config:
|
|||||||
# leave blank to generate an acronym of your community name during initialization
|
# leave blank to generate an acronym of your community name during initialization
|
||||||
community_slug: ''
|
community_slug: ''
|
||||||
|
|
||||||
|
# use_community_slug
|
||||||
|
# whether to use the community slug as a suffix for room aliases
|
||||||
|
use_community_slug: true
|
||||||
|
|
||||||
# sleep time between actions. you can drop this to 0 if your bot has no
|
# sleep time between actions. you can drop this to 0 if your bot has no
|
||||||
# ratelimits imposed on its homeserver, otherwise you may want to increase this
|
# ratelimits imposed on its homeserver, otherwise you may want to increase this
|
||||||
|
|||||||
@@ -46,24 +46,41 @@ class TestRoomUtils:
|
|||||||
assert result == True
|
assert result == True
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_validate_room_aliases_no_slug(self):
|
async def test_validate_room_aliases_slug_not_required_with_no_slug(self):
|
||||||
"""Test alias validation without community slug."""
|
"""Test alias validation without community slug."""
|
||||||
client = Mock()
|
client = Mock()
|
||||||
|
|
||||||
result = await validate_room_aliases(client, ["room1", "room2"], "", "example.com")
|
result = await validate_room_aliases(client, ["room1", "room2"], "", False, "example.com")
|
||||||
assert result == (False, [])
|
assert result == (True, [])
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_validate_room_aliases_success(self):
|
async def test_validate_room_aliases_slug_not_required_with_slug(self):
|
||||||
"""Test successful alias validation."""
|
"""Test successful alias validation."""
|
||||||
client = Mock()
|
client = Mock()
|
||||||
client.resolve_room_alias = AsyncMock(side_effect=MNotFound("Room not found", 404))
|
client.resolve_room_alias = AsyncMock(side_effect=MNotFound("Room not found", 404))
|
||||||
|
|
||||||
result = await validate_room_aliases(client, ["room1", "room2"], "test", "example.com")
|
result = await validate_room_aliases(client, ["room1", "room2"], "test", False, "example.com")
|
||||||
assert result == (True, [])
|
assert result == (True, [])
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_validate_room_aliases_conflicts(self):
|
async def test_validate_room_aliases_slug_required_with_no_slug(self):
|
||||||
|
"""Test alias validation without community slug."""
|
||||||
|
client = Mock()
|
||||||
|
|
||||||
|
result = await validate_room_aliases(client, ["room1", "room2"], "", True, "example.com")
|
||||||
|
assert result == (False, [])
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_validate_room_aliases_slug_required_with_slug(self):
|
||||||
|
"""Test successful alias validation."""
|
||||||
|
client = Mock()
|
||||||
|
client.resolve_room_alias = AsyncMock(side_effect=MNotFound("Room not found", 404))
|
||||||
|
|
||||||
|
result = await validate_room_aliases(client, ["room1", "room2"], "test", True, "example.com")
|
||||||
|
assert result == (True, [])
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_validate_room_aliases_conflicts_slug_not_required(self):
|
||||||
"""Test alias validation with conflicts."""
|
"""Test alias validation with conflicts."""
|
||||||
client = Mock()
|
client = Mock()
|
||||||
|
|
||||||
@@ -75,7 +92,23 @@ class TestRoomUtils:
|
|||||||
|
|
||||||
client.resolve_room_alias = AsyncMock(side_effect=resolve_side_effect)
|
client.resolve_room_alias = AsyncMock(side_effect=resolve_side_effect)
|
||||||
|
|
||||||
result = await validate_room_aliases(client, ["room1", "room2"], "test", "example.com")
|
result = await validate_room_aliases(client, ["room1", "room2"], "", False, "example.com")
|
||||||
|
assert result == (False, ["#room1:example.com"])
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_validate_room_aliases_conflicts_slug_required(self):
|
||||||
|
"""Test alias validation with conflicts."""
|
||||||
|
client = Mock()
|
||||||
|
|
||||||
|
def resolve_side_effect(alias):
|
||||||
|
if "room1" in alias:
|
||||||
|
return {"room_id": "!room1:example.com"} # Exists
|
||||||
|
else:
|
||||||
|
raise MNotFound() # Doesn't exist
|
||||||
|
|
||||||
|
client.resolve_room_alias = AsyncMock(side_effect=resolve_side_effect)
|
||||||
|
|
||||||
|
result = await validate_room_aliases(client, ["room1", "room2"], "test", True, "example.com")
|
||||||
assert result == (False, ["#room1-test:example.com"])
|
assert result == (False, ["#room1-test:example.com"])
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
|||||||
Reference in New Issue
Block a user