خطأ من نوع 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
إعجاب واحد (1)