You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨站点同步组及移除冗余成员的Python脚本故障排查

站点组及成员同步问题:移除Site2冗余成员失败

我正在两个站点间同步Groups及其成员,目前在移除Site2组中不存在于Site1组的用户时遇到问题,怀疑是代码缩进错误但始终无法解决。预期脚本可匹配双方邮箱,移除Site2组中Site1组没有的成员。

原代码

import json
import requests

api_key = "blahblah"
api_user = "johnwick"
token = "disdatokendontstealit"
url1 = "yolo.com"
ur2 = "yolo.web"

headers1 = {
    "X-KZO-Auth-AccessKey": api_key,
    "X-KZO-Accept-API-Versions": "1",
    "X-KZO-Auth-Username": api_user,
    "Content-Type": "application/vnd.api+json",
    "X-KZO-Pipeline-Action": "Process",
}

headers2 = {
    "Authorization": token,
    "Accept": "application/json",
    "Content-Type": "application/json",
}

get_bridge_groups_URL = f"{url1}/api/author/groups"
get_bridge_groups = requests.get(get_bridge_groups_URL, headers=headers1)
group_data = (
    get_bridge_groups.json()
)  ## These three lines go out and get Group data from Site1


for group in group_data["groups"]:
    group_name = group["name"]  ## Get the name of the group
    bridge_group_id = group["id"]  ## Get the id of the group
    bav_create_group_url = f"{bav_url}/api/groups"
    group_payload = {"groups": {"name": group_name, "description": ""}}
    create_bav_group = requests.post(
        bav_create_group_url,
        headers=headers2,
        json=group_payload,  ## Go create the Group with same name in Site2
    )
    if create_bav_group.status_code == 201:
        print(f"Group '{group_name}' created successfully!")
    else:
        print(
            f"Failed to create group '{group_name}'. Status code:",
            create_bav_group.status_code,
        )
    bav_group_data = create_bav_group.json()
    bav_group_id = bav_group_data["groups"][
        "id"
    ]  ## Get the ID of the new group in Site 2
    get_group_learners_url = (
        f"{url1}/api/learn/author/groups/{bridge_group_id}/learners"
    )
    get_group_learners = requests.get(
        get_group_learners_url, headers=headers1
    )  ## Get group members from Site 1
    groups_users_json = get_group_learners.json()
    for learner in groups_users_json["learners"]:
        try:
            bav_find_user_url = f"https://andrew-v5.instilled.com/api/users?q={learner['email']}"  ## Search and attempt to match user by email from Site1 in Site2
            bav_find_user = requests.get(bav_find_user_url, headers=headers2)

            bav_user_json = bav_find_user.json()
            username = bav_user_json["users"][0]["username"]
            enroll_in_bav_group_url = (
                f"https://andrew-v5.instilled.com/api/groups/{bav_group_id}/users"
            )
            enroll_in_bav_group = requests.post(  ## If user found in Site1, enroll into the newly created group in Site1
                enroll_in_bav_group_url,
                headers=instilled_headers,
                data=json.dumps({"users": [username]}),
            )
            print(f"{learner['email']} has been enrolled in '{group_name}'. Sweet!")
        except IndexError:
            print(f"User {learner['email']} was not found in BAV.") ## If user is not found by email, print that they are not in Site2.
    get_bav_group_learners_url = f"{bav_url}/api/groups/{bav_group_id}?include=users" ## Below here is where it starts to crap out, I'm attempting to get the new Group members from Site2 for the new Group and match them against the Group in Site1. If members exist in Site2 Group but not Site1 Group, I want to remove them from Site 2 Group.
    get_new_group_learners = requests.get(
        get_bav_group_learners_url, headers=instilled_headers
    )
    bav_group_users_json = get_new_group_learners.json()
    for user in bav_group_users_json["linked"]["users"]:
        email = user["email"]
        if email in {learner["email"]}:
            print(f"{learner['email']} is enrolled in BAV Group and Bridge Group")
        else:
            bav_user_delete_url = (
                f"{bav_url}/api/groups/{bav_group_id}/users/{username}"
            )
            bav_user_delete = requests.delete(
                bav_user_delete_url, headers=instilled_headers
            )
            print(
                f"{username} using email ({email}) has been removed from the BAV Group"
            )

问题诊断

  1. 变量作用域失效:移除冗余用户的循环中,learner变量仅在遍历Site1成员的循环内有效,循环结束后learner指向最后一个用户,无法代表Site1所有成员。
  2. 比对逻辑错误:if email in {learner["email"]}仅会匹配最后一个learner的邮箱,而非Site1所有成员的邮箱集合。
  3. 变量名不一致:代码中存在ur2(应为url2)、bav_url未定义、headers2与instilled_headers混用等语法错误,直接导致脚本运行失败。
  4. 未提前存储Site1成员列表:未将Site1组的所有成员邮箱收集为集合,无法高效比对Site2成员是否冗余。

修复后代码

import json
import requests

api_key = "blahblah"
api_user = "johnwick"
token = "disdatokendontstealit"
url1 = "yolo.com"
url2 = "yolo.web"  # 修正变量名
bav_url = "https://andrew-v5.instilled.com"  # 定义缺失的bav_url

headers1 = {
    "X-KZO-Auth-AccessKey": api_key,
    "X-KZO-Accept-API-Versions": "1",
    "X-KZO-Auth-Username": api_user,
    "Content-Type": "application/vnd.api+json",
    "X-KZO-Pipeline-Action": "Process",
}

headers2 = {
    "Authorization": token,
    "Accept": "application/json",
    "Content-Type": "application/json",
}

# 获取Site1的所有组
get_bridge_groups_URL = f"{url1}/api/author/groups"
get_bridge_groups = requests.get(get_bridge_groups_URL, headers=headers1)
group_data = get_bridge_groups.json()

for group in group_data["groups"]:
    group_name = group["name"]
    bridge_group_id = group["id"]
    
    # 在Site2创建对应组
    bav_create_group_url = f"{bav_url}/api/groups"
    group_payload = {"groups": {"name": group_name, "description": ""}}
    create_bav_group = requests.post(bav_create_group_url, headers=headers2, json=group_payload)
    
    if create_bav_group.status_code == 201:
        print(f"组 '{group_name}' 创建成功!")
    else:
        print(f"创建组 '{group_name}' 失败,状态码:", create_bav_group.status_code)
        continue  # 创建失败则跳过后续操作
    
    bav_group_data = create_bav_group.json()
    bav_group_id = bav_group_data["groups"]["id"]
    
    # 获取Site1当前组的所有成员,并收集邮箱集合
    get_group_learners_url = f"{url1}/api/learn/author/groups/{bridge_group_id}/learners"
    get_group_learners = requests.get(get_group_learners_url, headers=headers1)
    groups_users_json = get_group_learners.json()
    site1_member_emails = set()
    
    for learner in groups_users_json["learners"]:
        learner_email = learner["email"]
        site1_member_emails.add(learner_email)
        
        # 在Site2查找用户并加入组
        try:
            bav_find_user_url = f"{bav_url}/api/users?q={learner_email}"
            bav_find_user = requests.get(bav_find_user_url, headers=headers2)
            bav_user_json = bav_find_user.json()
            
            username = bav_user_json["users"][0]["username"]
            
            enroll_in_bav_group_url = f"{bav_url}/api/groups/{bav_group_id}/users"
            enroll_in_bav_group = requests.post(
                enroll_in_bav_group_url,
                headers=headers2,
                json={"users": [username]}  # 直接用json参数,无需手动dumps
            )
            
            print(f"{learner_email} 已加入 '{group_name}'。")
        except IndexError:
            print(f"未在BAV中找到用户 {learner_email}。")
    
    # 获取Site2当前组的所有成员,移除不在Site1中的用户
    get_bav_group_learners_url = f"{bav_url}/api/groups/{bav_group_id}?include=users"
    get_new_group_learners = requests.get(get_bav_group_learners_url, headers=headers2)
    
    if get_new_group_learners.status_code != 200:
        print(f"获取BAV组 '{group_name}' 成员失败,状态码:", get_new_group_learners.status_code)
        continue
    
    try:
        bav_group_users_json = get_new_group_learners.json()
        bav_group_users = bav_group_users_json.get("linked", {}).get("users", [])
    except KeyError:
        print(f"BAV组 '{group_name}' 成员数据格式异常")
        continue
    
    for user in bav_group_users:
        user_email = user["email"]
        user_username = user["username"]
        
        if user_email not in site1_member_emails:
            # 移除冗余用户
            bav_user_delete_url = f"{bav_url}/api/groups/{bav_group_id}/users/{user_username}"
            bav_user_delete = requests.delete(bav_user_delete_url, headers=headers2)
            
            if bav_user_delete.status_code == 204:
                print(f"用户 {user_username}(邮箱 {user_email})已从BAV组 '{group_name}' 移除")
            else:
                print(f"移除用户 {user_username} 失败,状态码:", bav_user_delete.status_code)
        else:
            print(f"用户 {user_email} 同时存在于Site1和Site2的 '{group_name}' 组中")

修复说明

  1. 修正变量错误:修复ur2为url2,定义缺失的bav_url,统一使用headers2避免变量混淆。
  2. 收集Site1成员集合:将Site1组的所有成员邮箱存入site1_member_emails集合,实现O(1)时间复杂度的比对。
  3. 调整比对逻辑:在移除冗余用户时,直接判断用户邮箱是否在Site1的邮箱集合中,而非依赖失效的learner变量。
  4. 增加容错处理:对组创建失败、成员数据获取失败、数据格式异常等情况增加判断,避免脚本崩溃。
  5. 优化请求写法:使用requests.post的json参数替代手动json.dumps,简化代码。

终端输出翻译

假设原终端输出内容翻译如下:

组'Test Group'创建成功!
test1@example.com已加入'Test Group'。
未在BAV中找到用户test2@example.com。
用户test3@example.com(邮箱test3@example.com)已从BAV组'Test Group'移除
用户test4@example.com同时存在于Site1和Site2的'Test Group'组中

内容的提问来源于stack exchange,提问作者warmrootbeer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 06:37:04