خطأ من نوع TypeError عند إرسال علم بمحتوى مخصص (أعلام require_message)

وصف الخطأ

عندما يختار المستخدم نوع علم يتطلب رسالة مخصصة (مثل notify_moderators، أو notify_user، أو أي علم مخصص تم إنشاؤه من قبل المسؤول مع تفعيل خيار “تطلب رسالة”)، ثم يملأ الرسالة ويرسل — يقوم المتصفح بإرجاع خطأ TypeError غير مُلتقط، ولا يتم إرسال العلم أبدًا.

خطوات إعادة إنتاج الخطأ

  1. انتقل إلى أي منشور في موضوع ما.
  2. انقر على زر العلم لفتح نافذة العلم المنبثقة.
  3. اختر نوع علم يتطلب رسالة (مثل “شيء آخر” / notify_moderators، أو أي علم مخصص تم إنشاؤه في الإعدادات → الأعلام مع تفعيل خيار “تطلب رسالة”).
  4. اكتب رسالة في مربع النص (طويلة بما يكفي لتجاوز الحد الأدنى للطول).
  5. انقر على زر الإرسال.

السلوك المتوقع

يتم إرسال العلم بنجاح.

السلوك الفعلي

تغلق نافذة العلم ولكن لا يتم إرسال العلم. يُظهر وحدة تحكم المتصفح:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'act')
    at n.create (flag.js:24:8)
    at S.createFlag (flag.gjs:205:32)
    at S.takeAction (flag.gjs:196:12)
    at m.perform (reviewable-bundled-action.gjs:47:17)
    at ej._boundaryActionHandler (select-kit.js:685:34)
    ...

تحليل السبب الجذري

ينشأ الانهيار في Flag#create (flag.js:24):

create(flagModal, opts) {
  const postAction = this.postActionFor(flagModal); // returns undefined
  // ...
  postAction.act(...) // ← TypeError: Cannot read properties of undefined
}

تبحث دالة postActionFor في PostFlag عن العلم المحدد باستخدام id الرقمي داخل actions_summary:

// post-flag.js
postActionFor(flagModal) {
  return flagModal.args.model.flagModel.actions_summary.find(
    (item) => item.id === flagModal.selected.id
  );
}

يُدرج الـ PostSerializer في الخلفية عنصر علم في actions_summary فقط إذا كان أحد القيم التالية صحيحة: can_act، أو count، أو acted:

result << summary if summary[:can_act] || summary[:count] || summary[:acted]

بالنسبة للأعلام التي تحتوي على require_message: true (وهي جميعها notify_type: true)، تقوم الدالة post_can_act? بتعيين can_act: false عندما يكون already_did_flagging صحيحًا — أي أن المستخدم قد قدم بالفعل أي علم من نوع الإشعار في ذلك المنشور. في هذه الحالة، يكون العنصر غائبًا عن actions_summary، فتُعيد postActionFor قيمة undefined، مما يؤدي إلى الانهيار.

في الوقت نفسه، تستخدم الدالة Post#flagsAvailable (التي تتحكم في ما يمكن للمستخدم اختياره في واجهة المستخدم) خريطة actionByName التي تم بناؤها عند تحميل الصفحة، لذا يمكن أن يظهر العلم كخيار قابل للاختيار حتى بعد عدم وجوده في actions_summary.

خطأ ثانوي

يوجد أيضًا مقارنة معطلة في flag.gjs:

const NOTIFY_MODERATORS_KEY = "notify_moderators"; // string

get notifyModeratorsFlag() {
  return this.flagsAvailable.find((f) => f.id === NOTIFY_MODERATORS_KEY);
  //                                      ^ number   ^ string — always false
}

f.id هو رقم بينما NOTIFY_MODERATORS_KEY هو نص، لذا فإن === تُرجع دائمًا false وتكون notifyModeratorsFlag دائمًا undefined. هذا يكسر منطق زر “علم للمراجعة” في flagForReview().

الحل المقترح

يجب أن تستخدم PostFlag#postActionFor خريطة actionByName (المفهرسة بـ name_key) بدلاً من البحث في actions_summary باستخدام id، وذلك بما يتوافق مع طريقة عمل TopicFlag#postActionFor بالفعل:

// post-flag.js
postActionFor(flagModal) {
  return flagModal.args.model.flagModel.actionByName[
    flagModal.selected.name_key
  ];
}

كما يجب أن تقارن notifyModeratorsFlag باستخدام name_key بدلاً من id:

get notifyModeratorsFlag() {
  return this.flagsAvailable.find((f) => f.name_key === NOTIFY_MODERATORS_KEY);
}

إصدار Discourse

2026.5.0-latest

قابل لإعادة الإنتاج على

  • أحدث فرع main
إعجابَين (2)

شكرًا للتقرير، سنقوم بالنظر فيه، ولا تتردد في إرسال طلب سحب (PR) أيضًا إذا أردت.

لقد حاولت إعادة إنتاج المشكلة محليًا لكنني لم أتمكن من ذلك. هل يمكنك إعادة إنتاجها إذا قمت بتفعيل الوضع الآمن؟

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

أعتقد أن وضع علم على الموضوع مرة واحدة لن يسبب هذه المشكلة لأن already_did_flagging يجب أن تكون false حينها. عادةً، لا يُسمح بوضع علم على نفس المشاركة مرة أخرى. لكن بعد وضع علم كـ “شيء آخر”، لا يزال بإمكانك وضع علم كـ “غير قانوني”. النتيجة في هذه الحالة هي

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

الآن تمكنت من تكرار المشكلة بنجاح:

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

  1. أنشئ موضوعًا يحتوي على بعض الردود المتداخلة
  2. ضع العلم على الرد كـ “شيء آخر” وقم بإرسال العلم
  3. انقر فوق أيقونة العلم مرة أخرى
    النتيجة المتوقعة: يكون خيار “إنه غير قانوني” هو المتاح فقط، تمامًا كما في المنشورات داخل المواضيع التي لا تعمل في وضع التداخل.
    النتيجة الفعلية: جميع أسباب وضع العلم ما عدا “شيء آخر” متاحة.
  4. اختر سببًا آخر، أرسل العلم، ثم افحص وحدة تحكم المتصفح
إعجاب واحد (1)

متأخرًا، لكنني أعمل على هذا الآن.

ما لا أراه هو «إنه غير قانوني» حتى في الوضع غير المتداخل. لقد قمت بتحديث الوضع المتداخل ليتطابق مع سلوك المواضيع غير المتداخلة، لكن كلاهما يظهران بهذا الشكل عند محاولة الإبلاغ مرة أخرى:

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

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

كما ترون في النافذة المنبثقة أدناه، تم بالفعل وضع علامة على المنشور للمراجعة من قبل المستخدم، وعند النقر على نافذة وضع العلامة مرة أخرى، يظهر ما يلي:


بالنظر إلى إعدادات موقعي، يبدو أن الخيار allow_all_users_to_flag_illegal_content هو ما يسمح للمستخدمين بوضع علامة “غير قانوني” حتى بعد اختيار خيار آخر.

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

آه، هذا حَلَّ المشكلة، شكرًا! يجب أن يُصدر الإصلاح قريبًا نسبيًا

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

إصلاح الخطأ الرئيسي موجود الآن في latest وينبغي أن يحل المشكلة. أي أنه يجب أن يكون مطابقاً لردود المواضيع غير المتداخلة.


قررت فصل هذا لأنه لا يتبع نفس السلوك، وسأقوم بإصلاحه أيضاً قريباً.

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

تم دمج المتابعة أيضًا. كانت المقارنة المعطوبة تعمل لصالحنا — إذا تم إصلاح المقارنة بشكل صحيح، لكان ذلك يسمح للمشرفين/المشرفين بتقديم إشارات دون سبب. نريد أن يكون السبب مطلوبًا لتقديم الإشارات، لذلك أزلت الكود بدلاً من إصلاحه لتجنب الالتباس في المستقبل.