Добавление атрибутов пользователя к сериализатору элемента каталога

Ко мне обратился клиент с просьбой создать каталог пользователей в виде карточек.

Поскольку он размещён на discourse.org, я изначально заявил, что это невозможно (не считая любых проблем с производительностью), так как атрибуты, необходимые для заполнения карточки пользователя, отсутствуют в объекте пользователя, сериализуемом вместе с элементами каталога.

Однако после дальнейшего обсуждения я пришёл к выводу, что один из подходов может заключаться в создании PR в основную ветку, который добавит атрибуты пользователя в сериализатор элементов каталога через настройку сайта. Идея состоит в том, что этот функционал будет полезен для различных стилей каталогов пользователей, требующих разных комбинаций атрибутов пользователя (пример ниже).

В ходе экспериментов я разработал относительно простой подход, который вы можете увидеть в этом diff:

https://github.com/discourse/discourse/compare/master...angusmcleod:directory_user_attribute_whitelist

А именно:

  1. Создать отдельный DirectoryItemUserSerializer (текущий «UserSerializer» внутри DirectoryItemSerializer всегда казался мне немного странным).

  2. Если администратор сайта выбрал какие-либо атрибуты пользователя для добавления:

    1. Создать сериализованного пользователя, чтобы воспользоваться защитными механизмами этого сериализатора, например, для атрибутов персонала, приватных или ненадёжных.

    2. Сериализовать все добавленные атрибуты, которые проходят фильтрацию UserSerializer.

Цели здесь следующие:

  1. Не изменять существующее поведение ни в каком виде.

  2. Сериализовать только запрошенные атрибуты.

Если вы поддерживаете этот подход/запрос, я завершу работу следующим образом:

  1. Добавлю валидацию для настройки сайта (то есть, чтобы убедиться, что введённая строка является атрибутом пользователя).

  2. Добавлю тесты.

Однако я решил сначала обсудить это с вами.

Пример

В качестве примера того, какой функционал это позволит реализовать, ниже приведён скриншот с моего локального окружения, где используется только это изменение в ядре + компонент темы, который переопределяет существующий каталог и использует модифицированный компонент карточки пользователя:

@sam Как думаешь, этот подход можно реализовать в PR?

Я думаю, что @blake и @awesomerobot работают с другим клиентом с похожими требованиями. Я в целом открыт к идее настройки сайта, подобной always_include_topic_excerpts.

Оговорка: я хотел бы, чтобы это было протестировано, и чтобы настройка сайта была скрытой.

Я знаю, что @david также проявлял интерес к этой проблеме. Я немного колеблюсь, но, возможно, более чистым долгосрочным решением будет:

  1. Добавить скрытые настройки сайта для «разрешения плагинам и темам запрашивать дополнительную сериализованную информацию» (по умолчанию выключено).
  2. Затем реализовать протокол в темах/плагинах для «запроса» этой дополнительной информации.

Преимущество здесь в том, что некоторые темы будут иметь дополнительную сериализованную информацию, а некоторые — нет.

Я хотел бы немного подождать с Дэвидом, прежде чем дать вам зеленый свет.

Как насчет того, чтобы заставить сериализатор каталога пользователей принимать новый параметр, например users.json?include_profile=true?

Тогда мы сможем добавить API для JS-плагинов, которое позволит темам добавлять этот параметр:

api.userListIncludeProfile(true)

«Профиль» будет включать все данные из обычного сериализатора пользователей (будучи осторожным, чтобы не вызвать запросы N+1). Я не думаю, что указание отдельных полей существенно повлияет на производительность, поэтому, на мой взгляд, стоит оставить всё простым.

Такой же подход можно применить и к спискам тем: ?include_excerpts=true.

Мне также нравится это решение, потому что оно означает, что «конфигурация сериализатора для каждой темы» не будет нарушена анонимным кэшем!

Что вы думаете, @sam?

Почти, но это работает некорректно, потому что при переходе на главную страницу сайта или по пути u у вас нет возможности добавить параметр в путь — нам нужно изменить значения по умолчанию :frowning:

О да :cry:

В таком случае, я думаю, что скрытая настройка сайта — хорошее начало. Было бы здорово сделать её зависимой от темы, но сначала нужно построить соответствующую инфраструктуру. Я всё ещё считаю, что булевая настройка «список пользователей включает профиль» будет проще для понимания.

Включает ли это такие свойства, как featured_user_badges, используемые в карточке пользователя?

Да, я так думаю — всё, что входит в стандартный сериализатор пользователя (при условии, что это можно сделать без возникновения проблемы n+1)

Отлично. Дайте знать, если вы считаете это pr-welcome и в каком виде, и мы с радостью подготовим его. С нашей стороны @fzngagan возьмёт это на себя.

Продолжим с одним скрытым параметром сайта типа boolean, который добавляет всю необходимую информацию.

Спасибо за предупреждение, @david. Я начну разбираться с этим с понедельника.

Один момент, который нужно прояснить, — это protocol для запроса дополнительных данных. Можем ли мы полагаться на настройку сайта на фронтенде для запроса данных или, как вы предложили, добавить еще один API в plugin-api?

Давайте упростим задачу: проигнорируйте мой пост о параметрах и JavaScript API.

Если настройка сайта включена на сервере, возвращайте дополнительную информацию. Если она отключена — не возвращайте.

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

Конечно. Компонент темы должен условно использовать дополнительные поля только когда настройка включена, верно?

Также сервер должен отправлять дополнительные поля только при включённой настройке.

@david Спасибо, Дэвид. Мы подготовим PR и свяжемся с вами.

@david Я сделал PR здесь

cc @angus

Закрываю этот вопрос. Мы решили не добавлять новые атрибуты к сериализатору каталога. Вместо этого мы значительно улучшили производительность сериализации пользователей. Мы вынесли карточки пользователей на отдельный маршрут и добавили новый маршрут, который возвращает несколько карточек за один запрос.

Пример использования этого нового маршрута можно найти в этом компоненте темы: