إلغاء استخدام `user.groups` في نموذج `User` بلغة JavaScript

هذا مرتبط بكل من The road to stable, then permanent, for granular_anonymous_and_logged_in_groups_permissions و Granular group-based permissions for anonymous and logged in users

في النواة (Core) وكذلك في العديد من القوالب (Themes) والإضافات (Plugins)، أصبح نمطًا شائعًا جدًا استخدام ما يلي:

const groupIds = this.currentUser.groups.map((g) => g.id);
const allowedGroupIds = this.siteSettings.some_group_setting.split("|").map((groupId) => parseInt(groupId, 10));

const hasPermission = allowedGroups.some((groupId) =>
  userGroupIds.includes(groupId)
);

if (!hasPermission) {
  return;
}

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

لجعل هذا أوضح، سنقوم بإعادة تسمية currentUser.groups/user.groups إلى currentUser.visibleGroups/user.visibleGroups في نموذج User وإلغاء استخدام الخاصية القديمة. أول طلب دمج (PR) للقيام بذلك هو DEV: Deprecate calling user.groups on client directly - Pull Request #42711 - discourse/discourse - GitHub .

توجد بدائل متعددة إذا كنت بحاجة إلى التحقق من صلاحية المستخدم بناءً على قائمة معرّفات المجموعات (Group IDs) على العميل في جافاسكربت:

للإضافات (Plugins)

قم بتمديد مُسلسل (serializer) current_user بخاصية جديدة، وتحقق من صلاحيات المستخدم باستخدام scope.in_any_groups? على جانب الخادم، والذي يغطي أيضًا المجموعات الوهمية (pseudogroups) مثل logged_in_users و anonymous_users:

add_to_serializer(
  :current_user,
  :has_some_permission,
  include_condition: -> do
    SiteSetting.plugin_enabled
  end,
) { scope.in_any_groups?(SiteSetting.group_list_setting_map) }

ثم يمكنك استخدام this.currentUser.has_some_permission على العميل.

للقوالب (Themes) والمكونات (Components)

لإعدادات القالب من النوع list مع list_type: group، يمكنك استخدام resolve_group_membership: true:

copy_button_allowed_groups:
  default: "1|3"
  type: list
  list_type: group
  resolve_group_membership: true

سيؤدي هذا إلى استبدال settings.copy_button_allowed_groups على العميل بـ settings.user_in_copy_button_allowed_groups (مع إضافة بادئة user_in_ للإعداد)، وهو قيمة منطقية (boolean) تُحسب على جانب الخادم بناءً على عضويات المستخدم في المجموعات.

يعمل هذا أيضًا مع إعدادات الكائنات (object settings) التي تحتوي على type: groups. أضف resolve_group_membership: true إلى الخاصية groups:

menu_sections:
  type: objects
  default:
    - name: section 1
      groups:
        - 1
        - 3
  schema:
    name: menu section
    properties:
      name:
        type: string
      groups:
        type: groups
        resolve_group_membership: true

يبدو الوصول إليها على هذا النحو:

for (const section of settings.menu_sections) {
  if (section.user_in_groups) {
    // المستخدم عضو في مجموعة واحدة على الأقل من المجموعات المحددة لهذا القسم.
  }
}

مرحباً مارتن،
هل ستدخل هذه التغييرات حيز التنفيذ عند دمج طلب الدمج (PR)، أم مع التحديث التالي بعد دمج طلب الدمج؟

لماذا هذا مهم؟ لن يؤدي هذا إلى كسر أي شيء. سيعرض ببساطة تحذيرًا في وحدة التحكم بالمتصفح، ليُنبه المطورين إلى تعديل أكوادهم.

لديّ مكوّنات سمة أعرف أنها تعتمد على هذا الأمر، وأردت توضيحًا. إذا كان الأمر مجرد تحذير وسيعمل لفترة من الوقت، فلن أكون قلقًا كثيرًا.

عادةً، ما يزال يُدعم الكود المُلغى حتى إصدار الدعم الموسّع التالي. وإلا، فلن تكون المنتديات التي تستخدمه قادرة على رؤية التحذير قبل حدوث الأعطال.

تم دمج طلب الإرسال (PR) الآن، لذا أصبح غير مستخدم:

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

لن يتحول هذا إلى إزالة دائمة لـ user.groups لفترة طويلة حتى نقتنع بأننا التقطنا جميع نقاط الاستدعاء، وحتى في ذلك الحين، سنبدأ أولاً بإظهار تحذير للمشرفين للمواقع التي لا تزال تحتوي على كود يستدعي الموقع القديم.