diff --git a/matrix_keycloak_bot.py b/matrix_keycloak_bot.py index 6fa8558..4ed71d7 100644 --- a/matrix_keycloak_bot.py +++ b/matrix_keycloak_bot.py @@ -48,6 +48,29 @@ def get_keycloak_client() -> KeycloakAdmin: ) +def check_group_membership(username: str, group_name: str) -> tuple[bool, str]: + """Checks if a user is already a member of a specified Keycloak group.""" + try: + kc = get_keycloak_client() + users = kc.get_users(query={"username": username, "exact": True}) + if not users: + return False, f"⚠️ Keycloak user `{username}` not found." + + user_id = users[0]["id"] + user_groups = kc.get_user_groups(user_id=user_id) + user_group_names = {g["name"].lower() for g in user_groups} + + if group_name.lower() in user_group_names: + return True, f"ℹ️ You are already a member of the `{group_name}` group." + + return False, "" + + except KeycloakError as e: + return False, f"⚠️ Keycloak API error: {str(e)}" + except Exception as e: + return False, f"⚠️ Unexpected error: {str(e)}" + + def add_user_to_kc_group(username: str, group_name: str) -> tuple[bool, str]: """Adds a Keycloak user to a target group.""" try: @@ -100,7 +123,6 @@ def get_requestable_groups(username: str) -> tuple[bool, str]: group_lines.append(f"* `{name}`") group_list = "\n".join(group_lines) - # Added extra \n before {group_list} to satisfy Markdown list block rules return True, f"**Available Groups:**\n\n{group_list}" except KeycloakError as e: @@ -132,7 +154,6 @@ async def send_markdown_message( msgtype: str = "m.text", relates_to: dict = None, ): - # Added "nl2br" extension to preserve single line breaks in chat messages html_body = markdown.markdown(md_text, extensions=["extra", "sane_lists", "nl2br"]) content = { @@ -213,6 +234,17 @@ async def on_message(client: AsyncClient, room: MatrixRoom, event: RoomMessageTe ) return + # Check if the user is already in the requested group before asking for approval + already_member, membership_msg = check_group_membership(kc_username, requested_group) + if already_member or membership_msg: + await send_markdown_message( + client, + room_id=room.room_id, + md_text=membership_msg, + msgtype="m.notice", + ) + return + admin_msg_body = ( f"📋 **Access Request**\n\n" f"**User:** `{matrix_user}` (KC: `{kc_username}`)\n"