Patreon v2 同步报告“N 个订阅,0 个用户已同步”——提取过程中从错误的资源读取了成员邮箱

免责声明:是的,我确实使用了 Claude 来帮助我修复这个问题:

当前运行的 Discourse 核心版本为提交 5ee8e24(2026-08-19)。Patreon 同步过程没有报错,但同步的用户数为零:

Patreon sync complete: 63 pledges, 0 users synced

API 响应均为 status=200,因此请求本身是正常的。在 Rails 控制台中进行追踪时,我发现插件构建的成员请求是正确的,并且确实在 member 资源中请求了 email 字段:

fields[member]=full_name,last_charge_date,last_charge_status,currently_entitled_amount_cents,patron_status,email

使用正确范围的创作者令牌(已授予 campaigns.members[email] 权限)直接调用该端点时,email 字段存在于 member 对象中,而不是 included 中的 user 对象上。对单个成员的获取也证实了这一点:

data.attributes.email        => "patron@example.com"   # 存在
included[].attributes.email  => (不存在)               # user 对象仅包含 full_name

因此,在 campaign 成员列表中,member.attributes.email 是有值的(我的 63 名成员中有 46 名;其余人限制了共享或为免费关注者),而 included 中的 user 条目根本没有 email 字段。

问题出在 Patreon::ApiVersion::V2.extractlib/api_version/v2.rb)中。它从 included 中的 user 对象构建 users 映射:

ruby

(member_data["included"] || []).each do |entry|
  if entry["type"] == "user" && entry["attributes"]["email"].present?
    users[entry["id"]] = entry["attributes"]["email"].downcase
  end
end

由于这些 user 对象从未携带 email,映射结果为空,导致每个成员的 email 匹配都失败,因此同步数为 0。

改为从 member 条目中读取 email(使用 member.relationships.user.data.id 中已有的 user id 作为键,这与用于 pledges 的 patron_id 相同)修复了我安装环境中的问题:同步数从 0 变为 46 users synced。我应用的更改如下:

diff

+            users[patron_id] = attrs["email"].downcase if attrs["email"].present?
             pledges[patron_id] = attrs["currently_entitled_amount_cents"]
             declines[patron_id] = attrs["last_charge_date"] if attrs["last_charge_status"] == "Declined"
           end
-
-          (member_data["included"] || []).each do |entry|
-            if entry["type"] == "user" && entry["attributes"]["email"].present?
-              users[entry["id"]] = entry["attributes"]["email"].downcase
-            end
-          end

我不确定完全移除 included 循环是否适用于所有情况——如果某些配置确实在 user 对象上接收 email,你可能希望保留它作为后备方案,而不是替换它。在此发布观察到的行为以及在此处有效的最小更改,希望这对大家有用,或者能指出正确的修复方向。