Создание плагина для связи Пользователь - Тег

Здравствуйте! Я работаю над разработкой конкретного плагина, но пока не могу определить, с чего начать (я изучил вводные материалы здесь, установил несколько простых плагинов и немного поигрался с их исходным кодом).

Настройка: У меня есть CSV-файл, содержащий несколько имен пользователей из системы и связанные с ними теги. Например, запись «user1, tag#1» означает: «user1 разбирается в теме tag#1». Один тег может быть связан с множеством пользователей, а один пользователь — с множеством тегов. Кроме того, этот CSV-файл будет обновляться время от времени (почти каждый день). Файл находится на том же сервере, где размещен экземпляр Discourse.

Как должен работать плагин в идеале: Я объясню это на примере CSV-файла и изображения.

CSV:

userOP, tag#1
userOP, tag#2
user2, tag#1

При наличии такого CSV-файла, если создается тема с любым из тегов, указанных в CSV (при этом автор темы может отсутствовать в списке), идеальный результат должен выглядеть следующим образом:

Кроме того, пользователь может видеть свои известные теги в виде кликабельных ссылок на своей панели профиля на дополнительной вкладке под названием «Известные теги»:

В идеале эта вкладка должна быть легко доступна через меню в левом верхнем углу:

То есть, исходя из связей, определенных в CSV-файле, для любого пользователя (автора темы или других), который публикует сообщения в теме с тегом, связанным с ним, должно отображаться небольшое текстовое уведомление или значок.

Я открыт к предложениям о том, как это реализовать.

Одна из задач, которую вам предстоит решить на стороне Rails, — добавить связи «пользователь/тег» в сериализатор, чтобы эти данные стали доступны фронтенду. Найдите другие плагины, которые вызывают add_to_serializer, или поищите эту функцию в исходном коде Discourse, так как она там хорошо задокументирована.

Затем вы сможете использовать плагин- outlet в Ember, чтобы добавить это на страницу. В документации по компонентам темы есть примеры такой реализации.

Я бы, вероятно, добавил маршрут для управления пользовательскими полями вместо использования CSV-файла, но если вы хотите работать через CSV, вам, возможно, понадобится задача, которая читает его каждый час или с другим интервалом. Для этого найдите плагин, в котором есть что-то в jobs/scheduled.

Существует репозиторий Discourse под названием all_the_plugins, который я иногда использую с grep, чтобы найти примеры подобных решений. Если вы пройдётесь по github.com/discourse, то сможете его найти.

Спасибо за информацию. На данный момент я представляю себе это так: мне нужно добавить к тегам пользовательское поле (например, tag_description) с названием attached_users. Для приведённого выше примера у тега #1 должно быть attached_users: [“userOP”, “user1”].

Затем мне каким-то образом нужно добавить это в сериализатор и разобраться, как отображать это в сообщении.

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

Использование assign кажется хорошей идеей. Я почти уверен, что вы можете добавлять пользователей через API. См. Как реверс-инжинирить API Discourse

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

Использование существующего поддерживаемого плагина будет гораздо проще, чем разработка и поддержка собственного.

Вы можете сделать это с помощью простого плагина.

Что нужно сделать

Плагин должен выполнять следующие действия:

  1. Добавить пользовательское поле known_tags (список строк).

  2. Добавить интерфейс в профиле пользователя, где можно редактировать known_tags. Не думаю, что необходимо создавать отдельную вкладку профиля для этого, но вы можете сделать это, если захотите. Если вы не хотите, чтобы пользователи редактировали это сами, просто сделайте поле доступным для редактирования только администраторами и обновляйте его в профилях пользователей на основе вашего CSV-файла.

  3. Добавить обработчик событий, который использует события before_create_post или post_created в PostCreator, чтобы добавлять нужный контент в пост на основе тегов темы.

Как это сделать

Части 1 и 2 очень похожи на примеры плагинов для других моделей в теме, ссылка на которую приведена ниже. Попробуйте разобраться по аналогии. Если вы совсем застрянете, спросите меня, и я подскажу.

Часть 3 также будет находиться в вашем файле plugin.rb. Она будет выглядеть примерно так:

on(:post_created) |post, opts, user|
  if post.is_first_post? && post.topic.tags.present?
     user_ids = UserCustomField.where(name: 'known_tags', value: post.topic.tags).pluck(:user_id)
     usernames = User.where(id: user_ids).pluck(:username)
     new_raw = post.raw + "something something #{usernames}"
     PostRevisor.new(post).revise!(
      user,
      {
        raw: new_raw,
        edit_reason: "some reason"
      },
      skip_validations: true,
      bypass_bump: true
    )
  end 
end

Попробуйте сделать это самостоятельно. Если вы совсем застрянете, я помогу. Я всегда охотнее помогаю, если вижу, что вы пытаетесь разобраться сами :slight_smile:

Большое спасибо за отличный план действий, я уже работаю по нему! Небольшой вопрос:

Должна ли эта часть выполняться вручную при таком подходе (под «вручную» я имею в виду добавление записей по одной через интерфейс)? В идеале я хотел бы добавить это через свой ключ администратора API, так как CSV-файл довольно большой и будет расти со временем.

Нет, это не обязательно должно делаться вручную. Существует довольно много способов заполнить пользовательские поля на основе CSV-файла. Всё зависит от того, как вы хотите обрабатывать обновления. Я бы предложил сначала выполнить остальные части и протестировать этот процесс на небольшом наборе данных. Затем, если вас устроит результат, можно добавить автоматический импорт CSV-файла. Оптимизация этой части — задача второго порядка.