from .db_logging import log_change from .entity import ensure_entity_active def _get_entity_type(cursor, entity_id): cursor.execute("SELECT type FROM entity WHERE id = %s", (entity_id,)) row = cursor.fetchone() return row["type"] if row else None def _validate_role(role): if not isinstance(role, str): raise TypeError("role must be a string") r = role.strip() if not r: raise ValueError("role must be a non-empty string") if len(r) > 10: raise ValueError("role must be at most 10 characters") return r def add_group_member(cursor, group_id, member_id, role): """Add a member to a group. Rules: - group_id must reference an active entity of type 'group' - member_id must reference an active entity (person/device/group) - role must be a non-empty string with max length 10 - duplicates are rejected """ ensure_entity_active(cursor, group_id) ensure_entity_active(cursor, member_id) if _get_entity_type(cursor, group_id) != "group": raise ValueError("group_id must reference an entity of type 'group'") r = _validate_role(role) cursor.execute( "SELECT 1 FROM group_member WHERE group_id = %s AND member_id = %s", (group_id, member_id), ) if cursor.fetchone() is not None: raise ValueError("Member is already in the group") cursor.execute( """ INSERT INTO group_member (group_id, member_id, role) VALUES (%s, %s, %s) """, (group_id, member_id, r), ) log_change(cursor, f"Added member {member_id} to group {group_id} as {r}") def get_members_of_group(cursor, group_id): ensure_entity_active(cursor, group_id) cursor.execute( """ SELECT member_id, role FROM group_member WHERE group_id = %s ORDER BY member_id """, (group_id,), ) return cursor.fetchall()