Устаревание использования 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

В ядре, а также во многих темах и плагинах, стала довольно распространена такая схема:

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;
}

Однако это неэффективный способ проверки прав пользователя. Пользователь может быть участником групп, которые ему не видны, поэтому они не сериализуются на клиенте и, следовательно, не могут использоваться последовательно и точно для проверок безопасности.

Чтобы сделать это более очевидным, мы переименовываем currentUser.groups/user.groups в currentUser.visibleGroups/user.visibleGroups в модели User и объявляем старое свойство устаревшим. Первый PR для реализации этого изменения — DEV: Deprecate calling user.groups on client directly - Pull Request #42711 - discourse/discourse - GitHub .

Если вам нужно проверять права пользователя на основе списка идентификаторов групп на клиенте в JavaScript, существует несколько альтернатив:

Для плагинов

Расширьте сериализатор current_user новым атрибутом и проверяйте права пользователя с помощью scope.in_any_groups? на стороне сервера, что также покрывает псевдогруппы, такие как 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.

Для тем и компонентов

Для настроек темы типа 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_), что является булевым значением, вычисляемым на стороне сервера на основе членства пользователя в группах.

Это также работает для объектных настроек с 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) {
    // Пользователь входит хотя бы в одну выбранную группу для этого раздела.
  }
}