按组+信任级别组合自动生成标题的最佳实践

您好,

我想找一种根据用户所属群组和信任等级自动分配用户头衔的最佳方法。例如:

  • 如果用户属于群组 A 且信任等级为 1,则其头衔应为“A TL1”
  • 如果用户属于群组 A 且信任等级为 2,则其头衔应为“A TL2”
  • 如果用户属于群组 B 且信任等级为 1,则其头衔应为“B TL1”
  • …以此类推

根据我目前找到的信息,主要方法是:

  1. 使用动态群组插件创建每个群组 + 信任等级组合的单独群组(例如 a-tl1a-tl2b-tl1 等)。
  2. 为这些群组中的每一个设置默认头衔。

虽然这似乎可行,但如果组合很多,则需要创建和维护大量的群组。

我的问题:

  • 这种设置(许多动态群组,每个群组都有自己的默认头衔)是保持头衔自动同步的最佳或唯一方法吗?
  • 是否有其他方法(使用 Discourse 核心功能、自动化或另一个插件)可以根据群组 + 信任等级等条件动态分配头衔,而无需管理如此多的额外群组?

非常感谢您提供的任何建议或分享的经验!预先感谢!

您是否可以根据组成员身份(A 或 B)配置标题,并有一个组件根据其信任级别添加标题?

我认为这样就不需要所有这些组合子组了 :thinking:

另一个想法:也许可以利用 插件(该插件根据信任级别自动将标题设置为标题)作为更复杂的基于信任级别和组成员身份的标题更新的基础。

3 个赞

感谢您的建议

遗憾的是,我本人没有任何编程经验,因此无法开发或修改插件。我已经联系了插件作者,询问是否可以添加此功能(将群组成员资格和信任级别合并用于标题),或者他们是否有任何建议。

如果这是用户的首要群组,我认为正如你在另一个话题中所提到的,这将使事情变得容易得多。

然后,你可以通过 user.primary_group 获取他们的首要群组,然后使用 user.title 设置头衔。

@joo 我添加了设置 add_primary_group_title(默认关闭),该设置:

  • 将用户的首要群组添加为标题
  • 标题后面的文本,例如:

          可以使用之前的设置进行编辑。

使用了 ask.discourse.com 的一些技巧。

附注:如果你想知道我是如何缩进“can”这个词的,我使用了  。抱歉了各位。

1 个赞

您好!感谢您的更新和支持!

可能我之前没有把需求解释清楚,所以想用一个易于理解的例子再次说明:

假设我们的论坛有两个主要分组:

  • 分组 A:设计师 (Designers)
  • 分组 B:开发者 (Developers)

对于每个分组,我希望不同信任等级的用户获得完全不同的头衔,例如:

对于设计师分组:
信任等级 1 → “初级设计师” (Junior Designer)
信任等级 2 → “设计师” (Designer)
信任等级 3 → “资深设计师” (Senior Designer)
信任等级 4 → “首席设计师” (Chief Designer)

对于开发者分组:
信任等级 1 → “初级开发者” (Junior Developer)
信任等级 2 → “开发者” (Developer)
信任等级 3 → “资深开发者” (Senior Developer)
信任等级 4 → “技术主管” (Tech Lead)

所以,如果某人属于“设计师”分组且信任等级为 3,那么他的头衔应该是“资深设计师”。
如果他属于“开发者”分组且信任等级为 2,那么头衔应该是“开发者”。

我希望能够为每个分组和信任等级设置这些规则,并在用户的分组或信任等级发生变化时自动分配头衔。

您能否就如何实现这一点提供一些建议,或者考虑将此作为您插件的新功能?

非常感谢!

1 个赞

另外,我正在我的测试站点上尝试实现这一点:http://ask.discourse.com/。
我没有编程经验,所以不确定是否可以自己实现。

我可能会在文本框中使用占位符值,例如 {group_nane},以便更容易编辑标题。我会看一下。

您可能想看看:

你好!

我已经修改了插件以满足我的需求,我想分享我所做的更改、我目前的工作流程以及一些问题/建议。


1. 我的修改

文件路径和内容:

文件: app/jobs/scheduled/update-all-titles.rb

# frozen_string_literal: true

module AddTitleBasedOnTrustLevel
  class UpdateTitles < ::Jobs::Scheduled
    every SiteSetting.update_title_frequency.hours

    def execute(args)
      group_titles = JSON.parse(SiteSetting.group_trust_level_titles || "{}")

      User.find_each do |user|
        # 跳过管理员和版主,不更新他们的头衔
        next if user.admin? || user.moderator?

        group_id = user.primary_group_id
        next unless group_id

        group = Group.find_by(id: group_id)
        next unless group

        group_key = group.name.downcase
        tl = user.trust_level

        titles = group_titles[group_key]
        next unless titles.is_a?(Array)
        next unless tl >= 1 && tl <= 4

        new_title = titles[tl]
        next unless new_title.present?

        user.update_column(:title, new_title) if user.title != new_title
      end
    end
  end
end

文件: config/settings.yml

plugins:
  add_title_based_on_trust_level_enabled:
    default: false
    client: true
  group_trust_level_titles:
    default: '{"designers": ["", "Junior Designer", "Designer", "Senior Designer", "Chief Designer"], "developers": ["", "Junior Developer", "Developer", "Senior Developer", "Tech Lead"]}'
    type: string
    client: true
    multiline: true
  update_title_frequency:
    default: 24
    type: integer

2. 我的测试方法

我目前通过rails console手动运行此逻辑来检查该功能是否正常工作。它确实会根据我的要求批量更新用户头衔。


3. 插件设置条目问题

/admin/plugins 页面上没有此插件的“设置”按钮。目前,要更改配置,我必须直接访问 /admin/plugins/add-title-based-on-trust-level/settings
是否有办法在插件页面上显示设置按钮或链接以便于访问?


4. 我的当前设置

这是我当前的 JSON 配置(我也会附上一张截图):

{
  "designers": ["", "Junior Designer", "Designer", "Senior Designer", "Chief Designer"],
  "developers": ["", "Junior Developer", "Developer", "Senior Developer", "Tech Lead"]
}


5. 问题 / 可能的改进

  • 这种方法(遍历每个用户并更新他们的头衔)是否存在性能风险,如果用户很多的话?是否有更好的最佳实践?
  • 关于优化,无论是针对计划任务还是管理员设置 UI,有什么建议吗?
  • 我的方法是否存在任何不安全或有问题的地方,我需要注意吗?

非常感谢您的辛勤工作和这个有用的插件!
如果您有任何建议,或者您计划将来改进组+信任级别头衔配置,我很想听听您的想法。

2 个赞

@joo 这个想法真棒!

如果你现在看看这个插件,我想我也这么做了(当时正在进行一些最终测试)。我看到你遍历了每个用户,但在大型论坛中,这可能需要很长时间。

所以,我做了一个 SQL UPDATE:

(我改编了 Ask Discourse 的查询并进行了修改)

这样,在设置 tl1_title_on_promotion 中,你应该可以使用类似 Junior {group_name} 的东西,这样标题就会变成 Junior Developer

请注意,为了使其生效,你还必须勾选 add_primary_group_title

1 个赞

感谢您的解释,我现在明白了您的 {group_name} 模板的工作原理。

但这正是我所说的逻辑差异。我的核心要求是能够根据不同的用户组,为相同的信任级别应用完全不同的标题结构。

例如,对于信任级别 3:

  • “Designers”组的标题应为“Senior Designer”。
  • “Developers”组的标题应为“Tech Lead”。

这两个标题具有完全不同的结构。

我曾尝试使用 AI 来实现此功能,但并未成功。我想知道您是否可以修改插件以支持这种更精细的逻辑?

啊,我想我误解你了。

那么你上面的代码是否奏效了?

不,我之前尝试过的 AI 代码也不起作用。设置好一切后,什么都没发生。

我想给你看看我最新尝试的完整代码。我希望你能发现我哪里做错了。

1. plugin.rb

# name: add-title-by-group-trust-level
# about: 使用 SQL 通过主要组 + 信任级别分配头衔
# version: 0.2
# authors: your-name

# 注意:我不确定是否需要在这里添加一个 'require' 行来加载作业文件。
# 我怀疑这可能是缺失的部分。
enabled_site_setting :add_title_by_group_trust_enabled

2. app/jobs/scheduled/update-all-titles.rb

module ::Jobs
  class UpdateTitles < ::Jobs::Scheduled
    every SiteSetting.update_title_frequency.hours

    def execute(args)
      return unless SiteSetting.add_title_by_group_trust_enabled

      mappings = JSON.parse(SiteSetting.group_trust_level_titles || '{}')

      User.transaction do
        mappings.each do |group_key, titles|
          next unless titles.is_a?(Array)

          (1...titles.size).each do |tl|
            title = titles[tl]
            next if title.blank?

            group = Group.find_by("LOWER(name) = ?", group_key.downcase)
            next unless group

            User.where(primary_group_id: group.id, trust_level: tl, admin: false, moderator: false)
                .where.not(title: title)
                .update_all(title: title)
          end
        end
      end
    end
  end
end

3. config/settings.yml

plugins:
  add_title_by_group_trust_enabled:
    default: false
    client: true
  group_trust_level_titles:
    default: '{"designers":["","Junior Designer","Designer","Senior Designer","Chief Designer"],"developers":["","Junior Developer","Developer","Senior Developer","Tech Lead"]}'
    type: string
    client: true
    multiline: true
  update_title_frequency:
    default: 24
    type: integer

我在站点设置中的配置方式:

我将此 JSON 粘贴到 group_trust_level_titles 设置中:

{
  "designers": ["", "Junior Designer", "Designer", "Senior Designer", "Chief Designer"],
  "developers": ["", "Junior Developer", "Developer", "Senior Developer", "Tech Lead"]
}

问题:

UpdateTitles 作业未出现在 Sidekiq 调度器 (/sidekiq/scheduler) 中。

但是,我按照 AI 提供的方​​法在 Rails 控制台中进行了测试,核心逻辑完全没问题,正确打印出了所有符合条件的用户。

这是我在 Rails 控制台中使用的测试脚本:

mappings = JSON.parse(SiteSetting.group_trust_level_titles || '{}')

mappings.each do |group_key, titles|
  next unless titles.is_a?(Array)

  (1...titles.size).each do |tl|
    title = titles[tl]
    next if title.blank?

    group = Group.find_by("LOWER(name) = ?", group_key.downcase)
    unless group
      puts "Could not find group: #{group_key}"
      next
    end

    users = User.where(primary_group_id: group.id, trust_level: tl, admin: false, moderator: false)
                .where.not(title: title)
    next if users.empty?

    puts "====== Group: #{group.name} Trust Level: #{tl} New Title: '#{title}' ======"
    users.each do |user|
      puts "User id:#{user.id}, username:#{user.username}, current title:'#{user.title}'"
    end
  end
end

所以看起来逻辑本身是正确的,但 Discourse 没有注册计划好的作业。无论如何,我尝试更改得越多,就越感到困惑……我不确定这是否是正确的方法,而且由于我不知道如何编码,所以感觉实现起来非常困难。你有没有更好的方法?

嗯……也许您想使用对象设置:

包含信任级别、组、标题等字段。

1 个赞

{“content”:“Just wanted to give an update and say thank you to everyone who helped.\n\nWith the latest changes, the plugin is now working exactly as I intended! It correctly assigns different titles based on the user’s primary group and trust level.\n\nI’m posting the final working code below. It seems to be correct, but since I’m not a developer, I was wondering if there are any areas for improvement or optimization that I might have missed.\n\napp/jobs/scheduled/update-all-titles.rb\n\n\n# frozen_string_literal: true\n\nmodule ::Jobs\n class AssignGroupBasedTitles < ::Jobs::Scheduled\n every SiteSetting.update_title_frequency.hours\n\n def execute(args)\n return unless SiteSetting.add_title_by_group_trust_enabled\n\n # 获取设置值,它现在是一个JSON字符串\n rules_json_string = SiteSetting.group_based_title_rules\n return if rules_json_string.blank?\n\n begin\n # 这是最关键的修复:手动将JSON字符串解析成Ruby数组\n rules = JSON.parse(rules_json_string)\n rescue JSON::ParserError\n # 如果JSON格式错误,则直接退出,防止任务失败\n Rails.logger.error(\"Group-Based Titles Plugin: Failed to parse group_based_title_rules JSON.\")\n return\n end\n \n return unless rules.is_a?(Array) && rules.present?\n\n User.transaction do\n rules.each do |rule|\n group_id = rule[\"group_id\"]\n trust_level = rule[\"trust_level\"]\n title = rule[\"title\"]\n\n next if group_id.blank? || trust_level.blank? || title.blank?\n\n User.where(primary_group_id: group_id, trust_level: trust_level)\n .where.not(title: title)\n .update_all(title: title)\n end\n end\n end\n end\nend\n\n\nconfig/settings.yml\n\nplugins:\n add_title_by_group_trust_enabled:\n default: true\n client: true\n\n # This MUST be type: objects. This was the source of the error.\n group_based_title_rules:\n type: objects\n default: []\n schema:\n properties:\n group_id:\n type: integer\n name: \"User Group\"\n component: \"group-chooser\"\n trust_level:\n type: integer\n name: \"Trust Level\"\n min: 1\n max: 4\n title:\n type: string\n name: \"Title\"\n \n update_title_frequency:\n default: 24\n type: integer\n\n\nplugin.rb\n\n# frozen_string_literal: true\n\n# name: add-title-by-group-trust-level\n# about: Assign titles based on primary group and trust level.\n# version: 2.1.0\n# authors: Your Name\n\nenabled_site_setting :add_title_by_group_trust_enabled\n\nafter_initialize do\n require_relative \"./app/jobs/scheduled/update-all-titles.rb\"\nend\n”,“target_locale”:“zh_CN”}

1 个赞