שיטות עבודה מומלצות לאוטומציה של כותרות לפי קבוצה + רמת אמון

שלום,

אני מחפש את הדרך הטובה ביותר להקצות אוטומטית תארים למשתמשים על בסיס שילוב של חברות בקבוצה ורמת אמון. לדוגמה:

  • אם משתמש נמצא בקבוצה A ויש לו רמת אמון 1, התואר שלו צריך להיות “A TL1”
  • אם משתמש נמצא בקבוצה A ויש לו רמת אמון 2, התואר שלו צריך להיות “A TL2”
  • אם משתמש נמצא בקבוצה B ויש לו רמת אמון 1, התואר שלו צריך להיות “B TL1”
  • …וכן הלאה

ממה שמצאתי עד כה, השיטה העיקרית היא:

  1. יצירת קבוצה נפרדת עבור כל שילוב של קבוצה + רמת אמון (למשל, a-tl1, a-tl2, b-tl1, וכו’) באמצעות תוסף הקבוצות הדינמיות (Dynamic Groups plugin),
  2. הגדרת תואר ברירת מחדל עבור כל אחת מהקבוצות הללו.

בעוד שזה נראה שעובד, זה דורש יצירה ותחזוקה של מספר רב של קבוצות אם ישנן שילובים רבים.

השאלות שלי:

  • האם ההגדרה הזו (קבוצות דינמיות רבות וכל אחת עם תואר ברירת מחדל משלה) היא הדרך הטובה ביותר או היחידה לשמור על תארים מסונכרנים באופן אוטומטי?
  • האם יש גישה אחרת (באמצעות ליבת Discourse, אוטומציות, או תוסף אחר) להקצאה דינמית של תארים על בסיס תנאים כמו קבוצה + רמת אמון, מבלי להצטרך לנהל כל כך הרבה קבוצות נוספות?

כל עצה או חוויות משותפות יתקבלו בברכה. תודה מראש!

Would it work for you to configure the title based on the group membership (A or B) and have a component that adds the title based on the trust level behind that?

I think then you wouldn’t need all those combined subgroups :thinking:

Another idea: Maybe the plugin which automatically sets the trust level as the title could be used as a base for a more complex title update based on trust level and group membership

3 לייקים

תודה על הצעותיך

לצערי, אין לי ניסיון בתכנות, ולכן איני יכול לפתח או לשנות תוספים. כבר פניתי למחבר התוסף כדי לשאול אם ניתן להוסיף את התכונה הזו (שילוב של חברות בקבוצה ורמת אמון לתארים), או אם יש לו עצות.

אם זו הקבוצה הראשית של המשתמש, אני חושב שכפי שציינת בנושא האחר, זה יקל על הדברים.\n\nלאחר מכן, תוכל לקבל את הקבוצה הראשית שלו דרך user.primary_group ואז להגדיר את הכותרת באמצעות user.title.

@joo I have added the setting add_primary_group_title (default off) that:

  • adds the user’s primary group as the title
  • text behind the title, eg:

         can be edited using the settings as before.

Used a hint of ask.discourse.com magic.

P.S. If you’re wondering how I indented the ‘can’, I used  . Sorry guys.

לייק 1

שלום! תודה על העדכון והתמיכה!

ייתכן שלא הסברתי את הדרישה שלי בבירור קודם לכן, לכן אני רוצה להבהיר אותה שוב עם דוגמה קלה להבנה:

נניח שלפורום שלנו יש שתי קבוצות עיקריות:

  • קבוצה א’: מעצבים
  • קבוצה ב’: מפתחים

עבור כל קבוצה, אני רוצה שמשתמשים עם רמות אמון שונות יקבלו תואר שונה לחלוטין, כך:

עבור קבוצת המעצבים:
רמת אמון 1 → “מעצב זוטר”
רמת אמון 2 → “מעצב”
רמת אמון 3 → “מעצב בכיר”
רמת אמון 4 → “מעצב ראשי”

עבור קבוצת המפתחים:
רמת אמון 1 → “מפתח זוטר”
רמת אמון 2 → “מפתח”
רמת אמון 3 → “מפתח בכיר”
רמת אמון 4 → “מוביל טכני”

לכן, אם מישהו נמצא ב"מעצבים" עם רמת אמון 3, התואר שלו צריך להיות “מעצב בכיר”.
אם הוא נמצא ב"מפתחים" עם רמת אמון 2, התואר צריך להיות “מפתח”.

אני רוצה להיות מסוגל להגדיר את הכללים הללו עבור כל קבוצה ורמת אמון, ולקבל תארים המוקצים אוטומטית כאשר רמות האמון או הקבוצות של המשתמשים משתנות.

האם יש לכם עצה כיצד להשיג זאת, או שתשקלו להוסיף זאת כתכונה חדשה בתוסף שלכם?

תודה רבה!

לייק 1

Also, I am trying to achieve this on my test site: http://ask.discourse.com/.
I don’t have programming experience, so I am not sure if it’s possible to implement this myself.

I might use a placeholder value, e.g. {group_nane} in the text box so that it can be easier to edit the title. I’ll take a look.

You might want to check out:

Hi!

I’ve modified the plugin to fit my needs, and I’d like to share what I did, my current workflow, and a few questions/requests for advice.


1. My Modifications

File path and content:

File: 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|
        # Skip admins and moderators, do not update their titles
        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

File: 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. How I Tested

I am currently manually running this logic via rails console to check if the function works. It does update user titles in bulk according to my requirements.


3. Plugin Settings Entry Issue

There is no “Settings” button for this plugin on the /admin/plugins page. Right now, to change the config, I have to visit /admin/plugins/add-title-based-on-trust-level/settings directly.
Is there a way to have the settings button or link appear on the Plugins page for easier access?


4. My Current Settings

This is my current JSON configuration (I will attach a screenshot as well):

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


5. Questions / Possible Improvements

  • Does this approach (looping through every user and updating their title) risk performance issues if there are a lot of users? Is there a better best-practice for this?
  • Any advice on optimization, either for the scheduled job or for the admin settings UI?
  • Is there anything unsafe or problematic with my method that I should be careful about?

Thank you very much for your great work and this useful plugin!
If you have any suggestions, or if you plan to improve group+trust level title config in the future, I would love to hear your thoughts.

2 לייקים

@joo Really neat idea!

If you look at the plugin now, I think I did this too (was running some final tests). I see you looped through each user, but in big forums, this may take a while.

So, I did a SQL UPDATE:

(I adapted Ask Discourse’s query and modified it)

This way, in the setting tl1_title_on_promotion, you should be able to use something like Junior {group_name}, so then the title would become Junior Developer.

Note that you would also have to tick add_primary_group_title for it to work.

לייק 1

תודה על ההסבר, אני מבין כעת כיצד תבנית {group_name} שלך פועלת.

אבל זו בדיוק הכוונה שלי לגבי ההבדל בלוגיקה. הדרישה המרכזית שלי היא להיות מסוגל להחיל מבני כותרות שונים לחלוטין עבור אותו רמת אמון, בהתבסס על קבוצות משתמשים שונות.

לדוגמה, עבור רמת אמון 3:

  • הכותרת עבור קבוצת “מעצבים” צריכה להיות “מעצב בכיר”.
  • הכותרת עבור קבוצת “מפתחים” צריכה להיות “ראש צוות טכני”.

לשתי הכותרות הללו יש מבנים שונים לחלוטין.

ניסיתי ליישם תכונה זו באמצעות AI, אך לא הצלחתי. תהיתי אם ייתכן שתוכל לשנות את התוסף כדי לתמוך בלוגיקה גרעינית יותר זו?

Ah, I think I misunderstood you then.

So did your code above work?

לא, גם הקוד הקודם שניסיתי עם בינה מלאכותית לא עבד. לאחר שהגדרתי הכל, שום דבר לא קרה כלל.

רציתי להראות לך את הקוד המלא מהניסיון האחרון שלי. קיוויתי שאולי תוכל לראות מה אני עושה לא בסדר.

1. plugin.rb

# name: add-title-by-group-trust-level
# about: assign titles via primary group + trust level using SQL
# version: 0.2
# authors: your-name

# Note: I'm not sure if I need a 'require' line here to load the job file.
# I suspect this might be the missing piece.
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).

עם זאת, בדקתי את זה בקונסולת 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 לא מזהה את המשימה המתוזמנת. בכל מקרה, ככל שאני מנסה לשנות את זה, זה נהיה יותר ויותר מבלבל… אני לא בטוח אם זו הגישה הנכונה, ומכיוון שאני לא יודע לקודד, זה מרגיש קשה מאוד ליישם את זה. יש לך שיטה טובה יותר?

Hmm… maybe you want to use object settings:

With fields like Trust Level, group, title.

לייק 1

רק רציתי לעדכן ולהודות לכל מי שעזר.

עם השינויים האחרונים, התוסף עובד כעת בדיוק כפי שהתכוונתי! הוא מקצה כותרות שונות בצורה נכונה בהתבסס על הקבוצה הראשית של המשתמש ורמת האמון שלו.

אני מפרסם את הקוד הסופי שעובד למטה. הוא נראה נכון, אבל מכיוון שאני לא מפתח, תהיתי אם ישנם אזורים לשיפור או אופטימיזציה שאולי פספסתי.

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

# frozen_string_literal: true

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

    def execute(args)
      return unless SiteSetting.add_title_by_group_trust_enabled

      # קבל את ערך ההגדרה, שהוא כעת מחרוזת JSON
      rules_json_string = SiteSetting.group_based_title_rules
      return if rules_json_string.blank?

      begin
        # זהו התיקון הקריטי ביותר: ניתוח ידני של מחרוזת JSON למערך Ruby
        rules = JSON.parse(rules_json_string)
      rescue JSON::ParserError
        # אם פורמט ה-JSON שגוי, צא מיד כדי למנוע כשל במשימה
        Rails.logger.error("Group-Based Titles Plugin: Failed to parse group_based_title_rules JSON.")
        return
      end
      
      return unless rules.is_a?(Array) && rules.present?

      User.transaction do
        rules.each do |rule|
          group_id = rule["group_id"]
          trust_level = rule["trust_level"]
          title = rule["title"]

          next if group_id.blank? || trust_level.blank? || title.blank?

          User.where(primary_group_id: group_id, trust_level: trust_level)
              .where.not(title: title)
              .update_all(title: title)
        end
      end
    end
  end
end

config/settings.yml

plugins:
  add_title_by_group_trust_enabled:
    default: true
    client: true

  # זה חייב להיות type: objects. זה היה מקור השגיאה.
  group_based_title_rules:
    type: objects
    default: []
    schema:
      properties:
        group_id:
          type: integer
          name: "קבוצת משתמש"
          component: "group-chooser"
        trust_level:
          type: integer
          name: "רמת אמון"
          min: 1
          max: 4
        title:
          type: string
          name: "כותרת"
  
  update_title_frequency:
    default: 24
    type: integer

plugin.rb

# frozen_string_literal: true

# name: add-title-by-group-trust-level
# about: Assign titles based on primary group and trust level.
# version: 2.1.0
# authors: Your Name

enabled_site_setting :add_title_by_group_trust_enabled

after_initialize do
  require_relative "./app/jobs/scheduled/update-all-titles.rb"
end
לייק 1