عمليات جماعية إدارية

ستجد أدناه مجموعة من العمليات المجمعة التي يمكن بدء تشغيلها من سطر الأوامر. ستحتاج إلى وصول SSH، لذا إذا كنت عميلاً مستضافًا، فستحتاج إلى الاتصال بفريق Discourse لتشغيل هذه الأوامر.

:warning: قبل العمل مع وحدة التحكم، من مهم للغاية أن يكون لديك نسخة احتياطية حديثة. فقد تحدث أخطاء دائمًا!

أول ما يجب فعله هو الدخول إلى حاوية موقعك:

cd /var/discourse
./launcher enter app

دليل إضافي:

تغيير حالة الموضوع


قبل تشغيل الأوامر التالية، قم بتشغيل rails c للدخول إلى وحدة التحكم.

  • إخفاء جميع المواضيع ضمن فئة معينة (باستثناء إجراء النشر)

    يمكنك استبدال visible بـ closed أو archived وتعديل قيم true/false حسب الحاجة

    cat_id = Category.find_by_slug('admins').id
    Topic.where(category_id: cat_id, visible: true).update_all(visible: false)
    
  • إخفاء جميع المواضيع ضمن فئة معينة (يشمل إجراء النشر)

    cat_id = Category.find_by_slug("admins").id
    Topic.where(category_id: cat_id, visible: true).find_each do |topic| 
      topic.update_status('visible', false, Discourse.system_user)
    end
    
  • إغلاق جميع المواضيع المنشأة قبل تاريخ محدد (يشمل إجراء النشر)

    Topic.where(closed: false).where("created_at <= '2015-01-01'").find_each do |topic| 
      topic.update_status('closed', true, Discourse.system_user)
    end
    

نقل المواضيع


نقل مجموعة من المواضيع من فئة إلى أخرى

rails c
topic_ids = [12,16,29]
cat_to = Category.find_by_slug('faq')
Topic.where(id: topic_ids).update_all(category_id: cat_to.id)
Category.update_stats

المستخدمين

حذف مجموعة فرعية من المستخدمين


حذف المستخدمين الذين لم ينشروا أبدًا ولم يزوروا الموقع منذ تاريخ محدد

rails c
User.joins(:user_stat).where("user_stats.post_count = 0 AND previous_visit_at <= '2016-05-20'::timestamp").destroy_all

تعليق مجموعة من المستخدمين بناءً على معايير


تحديد من سيتم تسجيله على أنه قام بتعليق المستخدمين

rails c
logger = StaffActionLogger.new(User.find_by(username_lower: "tshenry"))

إنشاء فترة تعليق وسبب

suspend_till = DateTime.new(2057,12,31)
reason = 'Completed Course'

في هذا المثال، ستكون معايير المستخدم هي عضوية المجموعة.

target_group = Group.find_by_name("summer_students")
users = User.joins(:group_users).where(group_users: {group_id: target_group.id})

تعليق كل مستخدم بناءً على القيم المحددة أعلاه:

users.find_each do |u|
  u.suspended_till = suspend_till
  u.suspended_at = DateTime.now
  u.save!

  logger.log_user_suspend(u,reason)
  putc '.'
end

تحديث أسباب تعليق المستخدمين


ربما قمت بتعليق مستخدمين أكملوا دورة ما (انظر المثال أعلى)، والآن تريد إضافة سنة الدورة حيث قمت بتدريس عدة سنوات.

UserHistory.where(action: 10, details: "Completed Course").update_all(details: "Completed 2018 Course")

إلغاء تعليق المستخدمين


إذا كنت بحاجة إلى إلغاء تعليق المستخدمين بشكل جماعي، مثل كونهم جزءًا من دفعة العام السابق ويعودون لهذا العام، فيمكنك فعل ذلك كما هو موضح أدناه. في المثال، نحن نبحث عن المستخدمين بمعرف المستخدم الخاص بهم.

user_list = [1, 3, 5, 7, 11]
users = User.where("id in (?)", user_list)

users.each do |user|
    user.suspended_till = nil
    user.suspended_at = nil
    user.save!
    StaffActionLogger.new(User.find(-1)).log_user_unsuspend(user)

    DiscourseEvent.trigger(:user_unsuspended, user: user)
end

تصدير/استيراد

تصدير/استيراد جميع إعدادات الموقع


لطباعة جميع الإعدادات التي تم تغييرها على موقعك ببساطة، قم بتشغيل:

rake site_settings:export

إذا كنت تريد تصدير الإعدادات إلى ملف:

rake site_settings:export > saved_settings.yml

إذا كنت تريد استيراد الإعدادات من ملف:

rake site_settings:import < saved_settings.yml

تصدير/استيراد الفئات


هناك خياران للتصدير وطريقة واحدة للتعامل مع الاستيراد.

تصدير مجموعة كاملة من الفئات

أولاً، احصل على قائمة بمعرفات الفئات الخاصة بك:

rake categories:list

ثم افصل معرفات الفئات بمسافات في مهمة التصدير rake. على سبيل المثال:

rake export:categories["12 6"]

تصدير هيكل فئات موقعك

هذا يشبه نسخ «الهيكل العظمي» لموقع Discourse الخاص بك. يتضمن كل فئة مع أي مجموعات مرتبطة بأذونات الفئة الحالية. إنه لا يتضمن المواضيع:

rake export:category_structure

إذا كنت تريد هيكل الفئات مع أي مجموعات مرتبطة بأذونات الفئة وأيضًا أي أعضاء في تلك المجموعات:

rake export:category_structure[true]

استيراد ملف فئة

استخدم اسم الملف المصدّر مثل المثال أدناه:

rake import:file["category-export-2019-05-16-052430.json"]

تصدير/استيراد المجموعات


تصدير جميع مجموعات المستخدمين

rake export:groups

تصدير جميع مجموعات المستخدمين بما في ذلك المستخدمين

rake export:groups[true]

استيراد ملف مجموعة
استخدم اسم الملف المصدّر مثل المثال أدناه:

rake import:file["group-export-2019-05-16-052430.json"]

تعيين الأذونات لعدة فئات


:warning: لاحظ أن هذا سيحذف أي قيود وصول موجودة قمت بتعيينها للفئات المعنية. تأكد من تضمين جميع الأذونات ذات الصلة.

  1. احصل على قائمة بالفئات مع معرفاتها

    rails c
    Category.all.pluck("name", "id")
    
  2. أنشئ مصفوفة بمعرفات الفئات التي تريد استهدافها.

    category_ids = [6,7,8,10]
    
  3. تغيير الأذونات. يمكن لدالة set_permissions استخدام المعلمات التالية: :full، :create_post، :readonly

    • إذن واحد. على سبيل المثال، جعل مجموعة من الفئات مخصصة للموظفين فقط:

      Category.where(id: category_ids).find_each do |category| 
       category.set_permissions(:staff => :full)
       category.save!
      end
      
    • أذونات متعددة. على سبيل المثال، جعل مجموعة من الفئات للقراءة فقط للمستخدمين العاديين:

      Category.where(id: category_ids).find_each do |category| 
        category.set_permissions(:everyone => :readonly, :staff => :full)
        category.save!
      end
      
    • أذونات مجموعة المستخدمين. على سبيل المثال، منح مجموعة واحدة أذونات كاملة ومجموعة أخرى للقراءة فقط لمجموعة من الفئات:

      artists_group = Group.find_by_name("artists")
      buyers_group = Group.find_by_name("buyers")
      Category.where(id: category_ids).find_each do |category| 
        category.set_permissions(artists_group.id => :full, buyers_group.id => :readonly)
        category.save!
      end
      

وسم جميع المواضيع بشكل جماعي بناءً على كلمة مفتاحية

ستسمح لك السكربت التالية بوسم المواضيع بناءً على وجود كلمة مفتاحية في عنوان الموضوع أو منشوراته. ابدأ بإنشاء مصفوفة من الكلمات المفتاحية:

rails c
keywords = ['apples','oranges']

بعد ذلك نحتاج إلى تعريف دالة:

def tag_by_keyword(word, tag_name)
  tag = Tag.find_by_name(tag_name) || Tag.create(name: tag_name)
  keyword_topics = Topic.joins(:posts).where("topics.title ~* :keyword or posts.raw ~* :keyword", keyword: "\\y#{word}\\y").distinct

  keyword_topics.each do |topic|
    if topic.tags.exclude?(tag)
      topic.tags << tag
    end
  end
end

وأخيرًا قم بتشغيل كل كلمة مفتاحية عبر الدالة. سيؤدي التالي إلى وسم كل موضوع ذي صلة بوسم يُدعى “fruit”:

keywords.each { |word| tag_by_keyword(word, 'fruit') }

وسم جميع المواضيع ضمن فئة بشكل جماعي


القالب: rake tags:bulk_tag_category["<tag>|<tag>",<category_id>]
سيكون هذا مفيدًا بشكل خاص عند محاولة تحويل فئة إلى وسم.

أولاً، استخدم مهمة rake التالية للعثور على معرف الفئة ذي الصلة.

rake categories:list

وسم جميع المواضيع في الفئة التي تحددها. في هذا المثال، ستقوم بوسم جميع المواضيع في الفئة بمعرف 6 بوسم “support”. :warning: سيؤدي هذا إلى إزالة جميع الوسوم الأخرى من كل موضوع.

rake tags:bulk_tag_category["support",6]

إلحاق جميع المواضيع في الفئة التي تحددها. في هذا المثال، ستقوم بإضافة وسم “support” إلى جميع المواضيع في الفئة بمعرف 6، مع الاحتفاظ بالوسوم الموجودة.

rake tags:bulk_tag_category["support",6,true]

نقل جميع المواضيع ذات وسم معين إلى فئة واحدة

عند محاولة إعادة هيكلة موقع Discourse الخاص بك، قد تجد أنك تريد نقل مجموعة من المواضيع دون تشغيل أي إشعارات. إحدى الطرق للقيام بذلك هي إنشاء وسم مؤقت، وتطبيقه على المواضيع المناسبة، ونقل المواضيع إلى فئة محددة باستخدام الكود أدناه، ثم أخيرًا حذف الوسم المؤقت.

احصل على الوسم.

rails c
tag = Tag.find_by_name("tutorial")

احصل على فئة الوجهة.

  • للفئات العادية:
cat_to = Category.find_by_slug('guides')
  • للفئات الفرعية:
cat_to = Category.find_by_slug('child-slug','parent-slug')

انقل المواضيع الموسومة إلى فئة الوجهة.

Topic.joins(:topic_tags).where("topic_tags.tag_id = ?", tag.id).update_all(category_id: cat_to.id)

قم بتحديث عدادات المواضيع للفئات المتأثرة.

Category.update_stats
CategoryTagStat.update_topic_counts

نقل جميع المواضيع من فئة إلى أخرى


ابحث عن معرفات الفئات باستخدام مهمة rake التالية:

rake categories:list

يجب أن تكون القيمة الأولى هي معرف الفئة البداية. ويجب أن تكون القيمة الثانية هي معرف فئة الوجهة.

rake categories:move_topics[15,6]
سكربت وحدة تحكم Rails
cat_from_id = XX # الفئة التي سيتم نقل المواضيع منها 
cat_to_id = XX  # الفئة التي سيتم نقل المواضيع إليها 
Topic.where(category_id: cat_from_id).update_all(category_id: cat_to_id)
Category.update_stats
CategoryTagStat.update_topic_counts

تغيير مالك جميع المواضيع في الفئات


ابحث عن معرفات الفئات باستخدام مهمة rake التالية:

rake categories:list

حدد المالك الجديد والفئات المراد العمل عليها. يجب أن تكون الفئات مصفوفة من معرفات الفئات، الفئات 1، 2 و 3 في المثال:

rails c
user = User.find_by(username_lower: "lowercase-username")
categories = [1, 2, 3]

احصل على معرفات جميع المواضيع للفئات المحددة وقم بتغيير مالك المنشور الأول في جميع المواضيع المطابقة.

topics = Topic.where(category_id: categories).pluck(:id)

topics.each do |topic|
  PostOwnerChanger.new(
    post_ids: Post.where(topic_id: topic).where(post_number: 1).pluck(:id),
    topic_id: topic,
    new_owner: user,
    acting_user: Discourse.system_user,
    skip_revision: true
  ).change_owner!
end

منح شارة لجميع أعضاء المجموعة


امنح شارة لجميع المستخدمين الذين ينتمون إلى مجموعة معينة. القيمة الأولى هي معرف المجموعة والثانية هي معرف الشارة.

rails c
Group.find_by_name("event_participants").id
Badge.find_by_name("event_badge").id
exit
rake groups:grant_badge[42,102]

:warning: لاحظ أن مهمة rake أعلاه تمنح شارة فقط، ولن تسحب شارة مُنحت سابقًا إذا لم يعد المستخدم جزءًا من المجموعة المحددة. إذا كنت بحاجة إلى سحب الشارات بشكل جماعي لجميع المستخدمين الذين لم يعودوا جزءًا من مجموعة، فيمكنك تشغيل ما يلي:

rails c

badge_id = Badge.find_by_name("Some Group Member").id

group = Group.find_by_name("Some_Group")

group_user_id = group.users.pluck("id")

userBadge = UserBadge.where.not(user_id: group_user_id).where(badge_id: badge_id)

userBadge.each do |ub|
  BadgeGranter.revoke(ub, revoked_by: Discourse.system_user)
end

exit

ضمان بقاء جميع المستخدمين في مستوى الثقة التلقائي الخاص بهم


لنفترض أنك قمت بتعيين مستوى الثقة الافتراضي للمستخدمين الجدد أو المدعوين إلى قيمة لا تعمل بالطريقة التي تتوقعها (مثل TL4). الآن تريد تغييرها بحيث يكون مستخدموك في مستوى الثقة الذي سيكونون عليه تلقائيًا، بناءً على إحصائياتهم الحالية. ستضمن الأوامر التالية أن جميع المستخدمين في مستوى الثقة الذي يجب أن يكونوا عليه وفقًا لـ Understanding Discourse Trust Levels. ملاحظة: لن يتأثر المستخدمون الذين لديهم مستويات ثقة مقفلة.

تأكد من تعيين جميع المستخدمين لمستوى الثقة الصحيح:

rails c
User.all.find_each do |user|
  Promotion.recalculate(user)
end

قم بتحديث إحصائيات المجموعة لتعكس التغييرات:

Group.ensure_consistency!

سكربتات صيانة المواضيع

توضح سكربتات Ruby التالية كيفية إجراء صيانة آلية للمواضيع بناءً على تواريخ النشاط ومعايير أخرى. تجمع هذه السكربتات بين استعلامات SQL لتحديد المواضيع وكود Ruby لتنفيذ الإجراءات عليها، ويجب تشغيلها عبر وحدة تحكم Rails لموقعك.

يتبع كل سكربت نمطًا مشابهًا:

  1. استعلام SQL يحدد المواضيع ذات الصلة
  2. كود Ruby يعالج كل موضوع ويطبق الإجراءات المطلوبة
  3. معالجة الأخطاء والتسجيل الأساسية

يمكن تخصيص هذه السكربتات عن طريق:

  • ضبط الفترات الزمنية (مثل ‘6 MONTH’، ‘1 YEAR’، ‘2 YEAR’)
  • تغيير اختيار الفئات لتتناسب مع هيكل المنتدى الخاص بك
  • تعديل الإجراءات التي سيتم اتخاذها (إغلاق، إخفاء، أو نقل)
  • إضافة شروط إضافية مثل عتبات عدد المنشورات أو المشاهدات

إغلاق وإخفاء ونقل المواضيع غير النشطة

يحدد هذا السكربت المواضيع التي تستوفي المعايير التالية:

  • في فئة محددة
  • مفتوحة
  • غير محلولة (باستخدام إضافة Discourse Solved)
  • لا يوجد نشاط حديث ضمن إطار زمني محدد

ثم يقوم بتنفيذ إجراءات متعددة:

  • إغلاقها،
  • إخفائها، و
  • نقلها إلى فئة مخصصة للمحتوى القديم
استعلام SQL
WITH topic_list AS (
    SELECT ua.target_topic_id, MAX(ua.created_at) "created_at"  
    FROM user_actions ua
    INNER JOIN topics t ON t.id = ua.target_topic_id
    INNER JOIN categories c ON c.id = t.category_id
    LEFT JOIN discourse_solved_solved_topics solved ON solved.topic_id = t.id
    WHERE t.closed = false
        AND t.category_id = [CATEGORY_ID]
        AND solved.topic_id IS NULL
        AND t.deleted_at IS NULL
    GROUP BY ua.target_topic_id
    HAVING MAX(ua.created_at) <= (CURRENT_DATE - (INTERVAL '[TIME_PERIOD]'))
    ORDER BY "created_at" DESC
)
    
SELECT '' AS total, target_topic_id AS topic_id, created_at 
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY created_at DESC
SQL + سكربت مدمج
sql = "WITH topic_list AS (
    SELECT ua.target_topic_id, MAX(ua.created_at) \"created_at\"  
    FROM user_actions ua
    INNER JOIN topics t ON t.id = ua.target_topic_id
    INNER JOIN categories c ON c.id = t.category_id
    LEFT JOIN discourse_solved_solved_topics solved ON solved.topic_id = t.id
    WHERE t.closed = false
        AND t.category_id = [CATEGORY_ID]
        AND solved.topic_id IS NULL
        AND t.deleted_at IS NULL
    GROUP BY ua.target_topic_id
    HAVING MAX(ua.created_at) <= (CURRENT_DATE - (INTERVAL '[TIME_PERIOD]'))
    ORDER BY \"created_at\" DESC
)
    
SELECT '' AS total, target_topic_id AS topic_id, created_at 
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY created_at DESC"

results = ActiveRecord::Base.connection.execute(sql)
user = Discourse.system_user
destination_category = Category.find([DESTINATION_CATEGORY_ID])

puts "Found #{results.count} topics to process"

results.each do |row|
    begin
    topic = Topic.find(row["topic_id"])
    
    # 1. نقل إلى فئة الوجهة
    topic.update!(category_id: destination_category.id)
    puts "#{topic.id} moved to destination category"
    
    # 2. إغلاق الموضوع
    topic.update_status('closed', true, user, until: nil)
    puts "#{topic.id} is closed"
    
    # 3. إخفاء الموضوع
    topic.update_status('visible', false, user, until: nil)
    puts "#{topic.id} is unlisted"

    # معالجة الأخطاء
    rescue => e
      puts "Error processing topic #{row["topic_id"]}: #{e.message}"
    end
end

puts "Process completed"

إغلاق المواضيع محلولة بدون نشاط حديث

يغلق هذا السكربت المواضيع المحلولة التي كانت خاملة لفترة محددة. يمكن أن يساعد هذا في الحفاظ على نظافة المنتدى مع الحفاظ على المواضيع المحلولة القيمة.

يحدد هذا السكربت المواضيع التي تستوفي المعايير التالية:

  • في فئة محددة
  • مفتوحة
  • محلولة (باستخدام إضافة Discourse Solved)
  • لا يوجد نشاط حديث ضمن إطار زمني محدد
استعلام SQL
WITH topic_list AS (
    SELECT ua.target_topic_id, MAX(ua.created_at) "created_at"  
    FROM user_actions ua
    INNER JOIN topics t ON t.id = ua.target_topic_id
    INNER JOIN categories c ON c.id = t.category_id
    INNER JOIN discourse_solved_solved_topics solved ON solved.topic_id = t.id
    WHERE t.closed = false
        AND t.category_id IN ([CATEGORY_IDS])
        AND t.deleted_at IS NULL
    GROUP BY ua.target_topic_id
    HAVING MAX(ua.created_at) <= (CURRENT_DATE - (INTERVAL '[TIME_PERIOD]'))
    ORDER BY "created_at" DESC
)
    
SELECT '' AS total, target_topic_id AS topic_id, created_at 
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY created_at DESC
SQL + سكربت مدمج
sql = "WITH topic_list AS (
    SELECT ua.target_topic_id, MAX(ua.created_at) \"created_at\"  
    FROM user_actions ua
    INNER JOIN topics t ON t.id = ua.target_topic_id
    INNER JOIN categories c ON c.id = t.category_id
    INNER JOIN discourse_solved_solved_topics solved ON solved.topic_id = t.id
    WHERE t.closed = false
        AND t.category_id IN ([CATEGORY_IDS])
        AND t.deleted_at IS NULL
    GROUP BY ua.target_topic_id
    HAVING MAX(ua.created_at) <= (CURRENT_DATE - (INTERVAL '[TIME_PERIOD]'))
    ORDER BY \"created_at\" DESC
)
    
SELECT '' AS total, target_topic_id AS topic_id, created_at 
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY created_at DESC"

results = ActiveRecord::Base.connection.execute(sql)
user = Discourse.system_user

puts "Found #{results.count} topics to process"

results.each do |row|
    begin
    topic = Topic.find(row["topic_id"])
     
    # إغلاق الموضوع
    topic.update_status('closed', true, user, until: nil)
    puts "#{topic.id} is closed"

    # معالجة الأخطاء
    rescue => e
      puts "Error processing topic #{row["topic_id"]}: #{e.message}"
    end
end

puts "Process completed"

أرشفة المواضيع المغلقة سابقًا

يحدد هذا السكربت المواضيع التي تم إغلاقها سابقًا قبل تاريخ محدد وينقلها إلى فئة الأرشيف مع إخفائها.

استعلام SQL
WITH topic_list AS (
    SELECT 
        t.id AS topic_id, 
        tt.execute_at AS closed_at
    FROM topics t
    INNER JOIN categories c ON c.id = t.category_id
    LEFT JOIN topic_timers tt ON tt.topic_id = t.id AND tt.status_type IN (1, 8)
    WHERE t.closed = true
        AND t.category_id IN ([CATEGORY_IDS])
        AND t.deleted_at IS NULL
        AND tt.execute_at IS NOT NULL
        AND tt.execute_at <= (CURRENT_DATE - INTERVAL '[TIME_PERIOD]')
    ORDER BY tt.execute_at DESC
)
    
SELECT '' AS total, topic_id, closed_at 
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY closed_at DESC
SQL + سكربت مدمج
sql = "WITH topic_list AS (
    SELECT 
        t.id AS topic_id, 
        tt.execute_at AS closed_at
    FROM topics t
    INNER JOIN categories c ON c.id = t.category_id
    LEFT JOIN topic_timers tt ON tt.topic_id = t.id AND tt.status_type IN (1, 8)
    WHERE t.closed = true
        AND t.category_id IN ([CATEGORY_IDS])
        AND t.deleted_at IS NULL
        AND tt.execute_at IS NOT NULL
        AND tt.execute_at <= (CURRENT_DATE - INTERVAL '[TIME_PERIOD]')
    ORDER BY tt.execute_at DESC
)
    
SELECT '' AS total, topic_id, closed_at 
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY closed_at DESC"

results = ActiveRecord::Base.connection.execute(sql)
user = Discourse.system_user
archive_category = Category.find([ARCHIVE_CATEGORY_ID])

puts "Found #{results.count} topics to process"

results.each do |row|
    begin
    topic = Topic.find(row["topic_id"])
    
    # 1. نقل إلى فئة الأرشيف
    topic.update!(category_id: archive_category.id)
    puts "#{topic.id} moved to archive category"
    
    # 2. إخفاء الموضوع
    topic.update_status('visible', false, user, until: nil)
    puts "#{topic.id} is unlisted"

    # معالجة الأخطاء
    rescue => e
      puts "Error processing topic #{row["topic_id"]}: #{e.message}"
    end
end

puts "Process completed"

مهام rake التدميرية


حذف فئات كاملة

سيسمح لك التالي بتدمير فئات متعددة، مع أي فئات فرعية ومواضيع تنتمي إلى تلك الفئات.

طباعة قائمة بمعرفات الفئات

rake categories:list

تدمير مجموعة من الفئات بناءً على معرفها

rake destroy:categories[10,11,12,18,30]

حذف جميع المواضيع في فئة

إزالة جميع الرسائل الشخصية

rake destroy:private_messages

تدمير جميع المجموعات

rake destroy:groups

تدمير جميع المستخدمين غير المسؤولين

rake destroy:users

تدمير إحصائيات الموقع

rake destroy:stats

إخفاء هوية جميع المستخدمين باستثناء الموظفين

rake users:anonymize_all

حذف نهائي لمجموعة من المنشورات

ستسمح مهمة rake التالية بالحذف الصارم لقائمة من المنشورات بناءً على معرفها. إذا كان المنشور هو المنشور الأول في موضوع، فسيتم حذف جميع المنشورات في ذلك الموضوع بشكل صارم. قبل أن تتمكن من تشغيل المهمة بنجاح، يجب تفعيل إعداد الموقع can_permanently_delete.

:warning: بمجرد حذف منشور بواسطة هذه المهمة، لن يعود موجودًا في قاعدة البيانات ولا يمكن استعادته.

هناك نهجان محتملان:

  • الخيار 1 – تمرير قائمة مفصولة بفواصل بمعرفات المنشورات كحجة

    rake destroy:posts[4,8,15,16,23,42]
    
  • الخيار 2 – تحديد ملف نصي بقائمة مفصولة بفواصل بمعرفات المنشورات (مثالي لمجموعات كبيرة من المنشورات).

    cat post_ids.txt | rake destroy:posts
    

لقد حاولت تضمين أكثر مهام rake فائدة في هذا الموضوع، ولكن هناك العديد من المهام الأخرى المرفقة مع Discourse. إذا كنت ترغب في رؤية قائمة شاملة، فيمكنك استخدام ما يلي:

جميع المهام التي تحتوي على أوصاف

rake --tasks

جميع المهام، بما في ذلك تلك التي لا تحتوي على أوصاف

rake -AT
70 إعجابًا
Performing bulk actions as a moderator
Ruby on rails console command
Backup only Site Settings
How to move all topics of 1 category to new tag
Error Message when editing large number of topics
Delete/Remove All Tags in Bulk
How To Apply signature to every user?
How can I directly edit Discourse database from a GUI?
Bulk open closed topics
Suggest favorite YouTube tutorials for Discourse Admins and Moderators
Error Message when editing large number of topics
How to truncate bounced email log
Is there a way to grant badge to a group of user?
What makes a successful volunteer Discourse sysadmin?
How to extend time of all suspended users by one command?
Is there a bulk administrative command to aprove users?
DiscoTOC mobile view does not work with Docs
How might we better structure #howto?
Moving from sub-categories to tags?
Moving from sub-categories to tags?
Automatic Admin settings backups
How to get rid of thousands of topics that have no value?
Setting the api key via console
Bulk Action on Users
Mass-edit (or review) category parameters
How to activate and unstage accounts for imported users
Moving a group to TL3
Bulk Category Creation via CSV
Adding bulk categories
Can I/how to convert a tag to a category?
Rake post without confirmation
A few questions about batch moving or deleting topics
Restoring Deleted Messages?
Bulk Ownership Change of First Posts by Tag – Script Review and Suggestions
What makes a successful volunteer Discourse sysadmin?
Understanding and using badges
How to recalculate all trust_levels?
Adding many categories
How to Delete Active Users whose Readtime is less or not logged in since long or not visited since long?
How to Reset Site Statistics or Recalculate?
A community template emphasizing place and intent
Docker attach gives empty new line
Change notification settings for all users per topic
Why is there a category that I can't modify
How to sort topics in Latest by creation date?
"Period" in tag
Bulk move many topics from one category to another
Can I disable choosing a default homepage in users' Interface settings?
Bulk delete all topics in a category
Update all users email watchlist with a (newly created) category
How to change owner of invite links?
Trust level names in spanish
Admin guide to tags in Discourse
Assign users a random digest time?
How to change language of all users?
Requesting help demoting users with invalid email addresses
Rake import category doesn't respect parent category
Is there a non-query way to remove a bulk of users from groups?
Set up file and image uploads to S3
Hide Muted Categories
Modify trust level for all users
Create user without sending invite
Removing specific staff action logs using the console
Is it possible to make database changes using postgres rather than rake?
Applying Watched Words to existing posts
Bulk changing subcategories doesn't select all topics?
How to update and unlock all groups?
CLI Command for Deleting Category
Apply preferences settings for all normal users globally
Switch all users to TL2
How to add multiple tags up front
Creating and configuring custom user fields
How to delete EVERYTHING from my forum and just leave the users?
Back up only the settings
Bulk mark messages and posters as spam
Bulk mark messages and posters as spam
Staff category permission change
Convert all existing topics in category to wikis
Migrate a phpBB3 forum to Discourse
Manage multiple Discourse instances from one place only
Merge categories
Bulk Importing Groups Fails
Automatically replacing some tags with categories on existing forum
Mass closing topics
User monetization with group access?
A way to trigger auto-tagging across all topics for a new watched word
Convert a category to private and add users to a specific group with access
How to mass remove PMs?
RSS Polling
Mass Revoking Badges
How to turn off forum except for staff
Cannot delete tag with 2k topics
Is it possible to limit TL0 to posting in one category?
Mass close existing topics older than x?
Mass close existing topics older than x?
How to import category with category permissions?
Bulk open closed topics
Get Error Oops The software powering this discussion forum encountered an unexpected problem after upgrade
How do I back up only forum configuration information?
Question about category populating with certain tags
How extensible can I make my installation in terms of sub domains and restricting membership to them?
Automatically re-categorize topics from an imported forum by targeting keywords in titles?
How to clear all historical statistics from dashboard
Create a category that's private to one group, but open to other groups
自定义表情符号能否支持批量删除?
Unable to Bulk Suspend/Deactivate Users in Rails Console on Discourse 3.5.0.beta5-dev
How to Disable ALL User-to-User DMs/Chat without breaking Other Features?
Move Some topics to New Instance
Structure and duplication of category contents intra discourse and between discourse sites
Is there a way to convert categories into tags?
Structuring an active support community migrating from Facebook
How to delete thousands of Personal Messages?
Multilingual Plugin :globe_with_meridians:
Moving from sub-categories to tags?
How to change topic date after import
Emoji Fluff
Export/import theme components in bulk?
Need To Reopen All Topics!
How to bulk delete old whispers
Add a tag to all topics in a category
How to Create a Script to "Bulk Remove" from a Group?
How to delete all warnings?
Marking multiple account as Suspended account
How can I directly edit Discourse database from a GUI?
Are conditions to get new Trust level cumulative?
Bulk Remove Members from a Group
Can't reverse silencing a category for a group
Assigning mod status to multiple users
Preserving site settings through migration
Limit volume of forum emails via admin
Is it possible to import a Discourse backup as a category inside an alredy existing discourse isntance?
Site rearrangement scripting: What's the best venue?
Recover deleted categories

@Taylor ماذا عن تحديث المواضيع دفعة واحدة بطابع زمني مختلف؟

لنفترض أنني أردت أن يتم تغيير جميع المواضيع في مثيل Discourse الخاص بي فورًا لتظهر كطابع زمني كما لو تم إنشاؤها اليوم، كيف يمكنني فعل ذلك؟

من المحتمل أن يكون تعديلاً على هذا الاستعلام:

(بافتراض أنها في فئة واحدة)

إعجاب واحد (1)

تم تقسيم 4 مشاركات إلى موضوع جديد: كيفية استيراد فئة مع أذونات الفئة؟

بالنظر إلى أن هذا الأمر يحتاج إلى التشغيل داخل حاوية Docker، وأن pwd الافتراضي داخل الحاوية عند تشغيل ./launcher enter app يبدو أنه /var/www/discourse، فإن الأمر الموصوف هنا يبدو غريبًا لعدة أسباب:

  • يتضمن site_settings مفاتيح الوصول السرية المستخدمة لـ S3 وواجهات برمجة التطبيقات الأخرى، ويبدو أنه لا ينبغي تخزين هذه المفاتيح في ملف تحت /var/www نظرًا لأن هذا هو الموقع التقليدي للملفات التي يتم تقديمها للويب.
  • نظرًا لأننا داخل الحاوية في هذا pwd الافتراضي، أتوقع أن يتم فقدان الملف المحفوظ هنا عند توقف الحاوية؟

من داخل الحاوية، استخدمت الأمر mount | grep ^/dev/ | grep -v /etc/ لتحديد أن الموقع /shared داخل الحاوية يبدو أنه يتوافق مع /var/discourse/shared/standalone على النظام المضيف. لذلك يبدو أن الأمر يجب أن يكون شيئًا كهذا؟

cd /var/discourse
./launcher enter app
rake site_settings:export | grep -v key | grep -v secret > /shared/site_settings_$(date "%Y-%m-%d-%H-%M-%S").yml

سيؤدي هذا إلى ترك الملف في موقع مثل /var/discourse/shared/standalone/site_settings_2024-08-14-15-53-11.yml على النظام المضيف.

لاحظ أن أوامر grep الإضافية الممررة هنا ستزيل أي أسطر تحتوي على الكلمة “key” أو “secret” لإزالة مفاتيح API ولكنها ستزيل أيضًا الأسطر التي تتضمن هذه الكلمات لأسباب غير حساسة.

هل هذا يبدو صحيحًا؟

صحيح، لكنني متأكد من أن Discourse لن تقدم الإعدادات. يمكنك تشغيل الأمر من أي دليل، ومن المفترض أنه إذا كنت تقوم بهذا النوع من الأشياء فأنت تفهم ما تفعله.

لذلك يمكنك فقط

cd /shared/
mkdir -p my-settings
cd my-settings
rake ...

قبل تشغيل مهمة rake.

بالتأكيد يحتوي التفريغ على المفاتيح، ولكن الكثير منها موجود كنص عادي في عدد من الأماكن بالفعل (على سبيل المثال، إذا اتبعت الإجراءات الموصى بها، فإن مفاتيح S3 الخاصة بك موجودة في app.yml).

نعم.

إعجابَين (2)

لم أكن أعلم أن مهام rake ستعمل خارج الدليل الحالي للتطبيق، هذا منطقي أكثر إذن، شكرًا لك

إعجاب واحد (1)

لا يزال الأمر يفاجئني!

ولكن يمكنك أيضًا وضع المسار الكامل للملف عند توجيهه إلى ملف.

وفقًا لهذه التعليمات، يمكنني استخدام

rake export:groups

لتصدير مجموعة المجموعات واستيراد مجموعات جديدة باستخدام نفس التنسيق. ومع ذلك، عندما أقوم بإنشاء مجموعة جديدة باتباع التنسيق المصدر، يشتكي الخيار --trace مما يلي:

ActiveRecord::RecordInvalid: Validation failed: You cannot allow membership requests for a group without any owners. (ActiveRecord::RecordInvalid)

(أحصل على نفس الخطأ إذا لم أقم بتضمين user_ids.)

إليك ملف الاستيراد الخاص بي:

{“groups”:[{“id”:352,“name”:“NewGroup1”,“created_at”:“2026-02-18T17:56:01.807Z”,“automatic_membership_email_domains”:“”,“primary_group”:false,“title”:null,“grant_trust_level”:null,“incoming_email”:null,“bio_raw”:“This is a NewGroup.”,“allow_membership_requests”:true,“full_name”:“NewGroup1”,“default_notification_level”:3,“visibility_level”:2,“public_exit”:true,“public_admission”:false,“membership_request_template”:null,“messageable_level”:3,“mentionable_level”:3,“members_visibility_level”:2,“publish_read_state”:false,“user_ids”:[1,2]}]}

لا أرى أي طريقة للإشارة إلى أي من المستخدمين هو مالك.

لقد أضفت سجلًا آخر لـ {"group_users":[...]} لتحديد مالك، ولكنني ما زلت أحصل على نفس الخطأ.

هل هذا يعمل؟ هل قام أي شخص باستيراد مجموعات جديدة بنجاح، وإذا كان الأمر كذلك، فما هو السر؟

إعجاب واحد (1)

آسف على التأخير قليلاً، لكن هذه هي مشكلتك. إذا جعلت هذه القيمة false إما عن طريق تعديل المجموعة قبل التصدير أو عن طريق تعديل ملف .json يدويًا، فستكون بخير.

المشكلة تكمن في أن تفعيل هذا الخيار يتطلب وجود مالك للتعامل مع الطلبات.

يمكنك بعد ذلك إصلاحه كما تشاء بعد الهجرة.