Theme-Component v Plugin: в чем разница

Может ли кто-нибудь прояснить разницу между этими тремя концепциями Discourse: theme-component, plugin и pluginAPI?

Особенно между theme-component и plugin. Если я хочу настроить свой форум, как мне понять, что именно нужно создавать?

(извините, если я упустил это различие в введении, но я не вижу его там)

Я не новичок в Discourse, но и не эксперт.

  1. Тема-компонент использует HTML, CSS и JavaScript для расширения базовой темы.
    Обращаю внимание на термин «базовая тема», так как обычно её просто называют «темой», и иногда люди не отмечают разницу, поэтому это нужно понимать из контекста. Тему и/или тему-компонент администратор может установить без остановки работы сайта, а если вы являетесь клиентом Discourse, вы также можете добавлять их. (список) Также см.: Руководство для начинающих по использованию тем Discourse

  2. Плагин использует Ruby и может выполнять практически любые задачи. Если вы клиент Discourse, у вас есть ограниченный набор разрешённых плагинов для активации. Однако если вы размещаете Discourse самостоятельно, вы можете добавить любые плагины, но будьте осторожны: я вижу множество сообщений о том, что кастомные плагины ломают сайт при обновлении. При активации плагины также не требуют перезапуска; возможно, перезапуск потребуется только при первой установке. Другие могут уточнить, так как мой опыт работы с плагинами ограничивается их активацией через админ-меню. (список) Также см.: Руководство для начинающих по созданию плагинов Discourse — Часть 1

  3. Я не разрабатывал плагины, поэтому предполагаю, что вы имеете в виду Ruby-модуль Discourse API. См.: Use the Discourse API ruby gem

  4. Также существует API, которое включает вебхуки и обычно используется с помощью curl или другого языка программирования. Это удобно, так как освобождает от необходимости использовать Ruby.

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

Надеюсь, это помогло.


РЕДАКТИРОВАНИЕ

Бонусный раунд, если вы хотите полностью погрузиться в разработку для Discourse.

См.: Как начать создавать вещи для Discourse, если вы новичок (как и я)

Чтобы дополнить ответ от @EricGT, который уже хорошо объясняет суть:

  • Тема или компонент темы — это, по сути, способ изменения любой части клиентского приложения Discourse на базе EmberJS. Это может быть так же просто, как настройка HTML или CSS, или так же сложно, как добавление нового функционала. Темы работают более gracefully: если что-то сломается, ваш сайт не обязательно полностью перестанет работать.
  • Плагин в первую очередь влияет на серверную часть приложения на Rails, но также включает в себя все возможности темы и возможность влиять на приложение EmberJS, хотя это гораздо сложнее. Сбои плагинов обычно обрабатываются менее gracefully, поэтому, если вы можете реализовать что-то в теме, начните с неё. Однако плагин необходим, если вам нужен пользовательский маршрут или хранение данных.
  • pluginAPI — это клиентский API, который темы и компоненты тем могут использовать для более удобного изменения конкретных частей клиентской части Discourse.

Лучшее место для начала кастомизации вашего сайта — это тема. Вот несколько полезных ресурсов:

Руководство для дизайнера по темам Discourse
Руководство разработчика по темам Discourse
Руководство для начинающих по использованию Theme Creator и Theme CLI для создания темы Discourse

Спасибо, ребята. Это полезно. Я понимаю ключевое различие так:
– если вы хотите изменить что-то, что касается только фронтенда, создайте тему.
– если вы хотите изменить что-то, что требует взаимодействия с бэкендом, создайте плагин.

Правильно ли я понимаю?

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

  1. Проверить, является ли пользователь модератором категории (это требует обращения к бэкенду за информацией о пользователе и категории).

  2. Если пользователь является модератором, показать кнопку закрепления (это фронтенд).

  3. Если пользователь нажимает кнопку закрепления, переместить тему наверх (точно не уверен, где именно это происходит в коде Discourse — возможно, и фронтенд, и бэкенд?).

Здесь, поскольку мне нужно взаимодействовать с бэкендом (вероятно, в пункте 1, возможно, также в пункте 3?), мне придётся использовать плагин. Правильно ли я понимаю?

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

Вы имеете в виду, что программный ответ на вопрос «Является ли этот пользователь модератором этой категории» потребует работы с несколькими файлами как на фронтенде, так и на бэкенде? Хм…

В теме вы должны иметь возможность определять, является ли пользователь модератором, а также выполнять вызовы бэкенда, если API Discourse предоставляет конечную точку, доступную для вызова с фронтенда (в конце концов, тема может использовать JavaScript), поэтому, вероятно, вам не понадобится плагин для [1]. Он потребуется только в том случае, если нужно изменить поведение бэкенда или предоставить новый API.

Однако, скорее всего, плагин понадобится для [3], потому что, как отметил @merefield, это касается прав и безопасности (если бэкенд блокирует модератору закрепление темы, вам придётся изменить это, чтобы разрешить такую возможность).

Как я уже сказал выше, для самой проверки (определения, является ли пользователь модератором) плагин, вероятно, не потребуется, но он, скорее всего, понадобится для действия по разрешению пользователю закреплять категорию. Если в Discourse есть опция, позволяющая любому модератору закреплять темы (не знаю, есть ли такая), то плагин не понадобится (но и тема, вероятно, тоже не нужна, если только кнопка закрепления не отображается модераторам, и вы используете тему исключительно для того, чтобы показать её модераторам и вызвать конечную точку через JavaScript при нажатии на кнопку закрепления).

Это очень полезно в отношении тем против плагинов, а также в отношении конкретного примера, который я привёл. Спасибо.

До сих пор мой подход к внесению изменений заключался в том, чтобы разбираться в деталях кода Discourse (где определён этот объект, что управляет этим шаблоном, где находится логика, обрабатывающая это действие и т.д.). Но это продвигается медленно.

Я думаю, что, вероятно, более эффективным путём будет сфокусироваться на API. Таким образом, мне не нужно разбираться во всех деталях зрелого кода Discourse, и я смогу сосредоточиться на создании темы, а не плагина, или, возможно, просто вносить изменения через панель «Настройка».

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

Чтобы оставаться в рамках приведённого примера: если пользователь является модератором категории, разрешить этому пользователю закреплять темы на странице категории.

Могу ли я сделать это без плагина? Позвольте мне попробовать набросать план:

1. Является ли пользователь модератором категории?

В данный момент я не вижу в API ничего, что позволяло бы узнать, является ли пользователь модератором категории. Я ожидал найти это в GET-запросе для получения информации о категории, но такого запроса там нет. Или, возможно, в GET-запросе для получения информации о пользователе, но там я не вижу списка категорий, модератором которых является пользователь.

Могу ли я добавить эти данные?

Или, альтернативно, возможно, я могу создать пользовательское поле (custom_field) для пользователя или категории, чтобы идентифицировать статус модератора, а затем делать API-запрос к этому пользовательскому полю при загрузке страницы категории.

2. Если пользователь является модератором, показать кнопку закрепления.

Если я смогу ответить на вопрос (1), то предполагаю, что смогу просто добавить эту кнопку с помощью фронтенд-скриптов (JavaScript) и CSS, отображая её, если пользователь является модератором.

3. Пользователь (который является модератором) нажимает кнопку, и это закрепляет тему.

В API темы действительно имеют признак «pinned» (булев тип). Я предполагаю, что это соответствует тому, закреплена ли тема в своей категории, так как выглядит так, будто у каждой темы только одна категория.

Так что здесь, когда модератор нажимает кнопку «Закрепить», я, вероятно, могу обновить статус «pinned» темы на True. Если это не сработает, пользовательские поля также могут стать решением (хотя я не вижу, как добавлять пользовательские поля к теме).


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

Звучит ли это правильно?

Вы нашли: Как провести реверс-инжиниринг API Discourse

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

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

– можно ли использовать API для добавления новых полей в запись? Например, могу ли я через API добавить пользовательское поле к теме? (На мой взгляд, темы обычно не содержат пользовательских полей)

Я бы поискал в базе данных.

В базе данных есть таблица posts, и вы могли бы добавить туда поле, но тогда вы выйдете за рамки официальной поддержки и не получите помощи.

Спасибо — всё это очень полезно.

Какую именно базу данных вы имеете в виду?


Для подтверждения: моя идея состоит в том, чтобы использовать API для выполнения некоторых задач, которые иначе потребовали бы плагина. Например, мой сайт сам будет делать запрос к API, чтобы определить, является ли пользователь (или группа, в зависимости от ситуации) модератором категории. Этот вызов будет прописан в панели настройки, в теме или в плагине.

Чтобы выполнять такие вызовы, мне потребуется аутентификация, что, как я понимаю, требует создания ключа API из админ-панели. Процесс создания ключа API в админ-панели требует указания «Описания» и «Уровня пользователя» — я не совсем понимаю, как это применимо в данном случае. В моём случае я хочу, чтобы моё приложение делало вызов API. Он не выполняется от имени конкретного пользователя. Возможно, я что-то неправильно понимаю.

Подскажите, какой уровень пользователя подходит для такого вызова API, или что мне следует указать в этом поле?

При установке Discourse согласно стандартной инструкции система работает в Docker-контейнере. Сохранение данных обеспечивается с помощью базы данных PostgreSQL.

См.: Плагин Data Explorer

Если у вас есть права администратора, вы можете скачать одну из резервных копий — это сжатый SQL-дамп в архиве tar.gz. Вы можете использовать этот SQL-файл для загрузки данных в другую базу данных PostgreSQL и выполнить ещё больше операций.

Я никогда не создавал темы или плагины, не использовал API из Ruby и не работал с API ни на каком другом языке программирования. У меня есть доступ администратора к рабочему сайту, и именно через него я получил доступ к резервной копии. Кроме того, я программирую на Prolog, и именно с его помощью я подключаюсь к данным и использую их для разбора постов с помощью DCG. Если вы знаете BNF, то DCG не сильно отличается, но для более сложных частей нужно понимать синтаксическое унифицирование и обратную цепочку выводов.

Спасибо. Я займусь этим вопросом отдельно.

Нет, так как права доступа для каждого действия контролируются сервером.

Вам стоит изучить возможность переопределения функций в lib/guardian/ и lib/guardian.rb, чтобы разрешить модераторам конкретной категории закреплять темы, а затем использовать те же механизмы, что и в JavaScript темы (но в плагине), для изменения интерфейса, чтобы опция «закрепить тему» появлялась при необходимости.

Ах, понятно. Значит, использование API для этой задачи, скорее всего, не сработает (ваш ответ, возможно, сэкономит мне много времени).

Я мог бы реализовать это немного иначе, чем обычное закрепление. Вместо этого я бы предоставил определённым пользователям права «владельца» категории, что позволило бы им выделять определённые темы в этой категории.

Вот как я бы это сделал через JSON API: из моей панели настройки я бы назначил соответствующим пользователям пользовательское поле (например, category-name: owner) или что-то подобное. Затем, при загрузке страницы категории, я бы вызвал API для проверки пользователя; если у него есть это пользовательское поле, показывать кнопку «выделить», а при нажатии на неё назначать тему в группу выделенных категорий (также пользовательское поле для этой категории).

Это лишь набросок — нет необходимости подтверждать каждый шаг по отдельности (при написании кода мне всё равно, возможно, придётся что-то скорректировать). Но мой текущий вопрос: сработает ли такой способ использования JSON API, особенно для создания и получения пользовательских полей внутри моего приложения Discourse?

Уважаемый @JQ331,

Но мой текущий вопрос: может ли такой способ использования JSON API — особенно для создания и получения пользовательских полей внутри моего приложения Discourse — работать?

Вашим вопросам о различиях между компонентом темы, плагином и API Discourse уже даны отличные ответы, и я сомневаюсь, что смогу добавить что-то значимое; однако вот ещё один взгляд на ситуацию, который может оказаться полезным (а может и нет):

И компоненты тем, и плагины используют хуки шаблонов (хуки плагинов) для выполнения кода в жизненном цикле Ember.js (что, кстати, полезно изучить).

Кроме того, API Discourse доступен как для компонентов тем, так и для плагинов.

API по сути предоставляет подмножество, но не все, данные из лежащей в основе базы данных PostgreSQL.

При разработке функциональности хорошей идеей будет начать с API и определить, доступны ли нужные вам данные через него.

Если есть какие-то данные, которые вам нужны, но которых нет в API, вам следует изучить базу данных PostgreSQL, чтобы проверить, существуют ли эти данные в базе.

Если дополнительные нужные вам данные существуют в базе данных, то вам нужно сделать их доступными, и обычно это означает добавление данных в сериализатор данных Discourse и расширение API.

Сериализатор данных — это просто процесс создания JSON-объекта, который предоставляется через API. Его можно расширить, добавив больше объектов.

Чтобы изучить базу данных PostgreSQL, я предполагаю, что существует множество способов сделать это (например, читая код на GitHub), но я делаю это, подключаясь к базе данных напрямую, просматривая таблицы в базе, изучая их структуру и определяя, какие поля есть в каждой таблице (используя базовый SQL).

Итак, чтобы подытожить (и сохранить краткость): нам нужны как API, так и таблицы базы данных в качестве ориентиров. В общем случае, когда вы хотите «расширить API», добавив данные, которые не предоставляются API из коробки (OOTB), мы создаём для этого плагин; после этого эти данные становятся доступными вместе с расширенным API, и мы можем использовать их как в компонентах тем, так и в плагинах.

Надеюсь, этот взгляд на ситуацию оказался полезным хотя бы в какой-то мере.

Исключительное объяснение. Большое спасибо за этот ответ. Он подчеркивает то, чего я раньше не осознавал:

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

Кажется, одним из хороших примеров данных, недоступных через API, являются владельцы группы. Я так говорю, потому что (касательно доступа к владельцам группы):

Один момент, вызывающий путаницу: в API Discourse, когда вы получаете информацию о конкретной группе, одним из возвращаемых признаков числится "is_group_owner": true, так что не совсем понятно, что это должно означать…

Но, похоже, чтобы получить владельца группы, мне нужно сериализовать признак владельца группы.


Есть ли хорошие примеры использования сериализатора Discourse? Я видел этот, но, учитывая его важность, руководство с несколькими примерами было бы чрезвычайно полезным.

Самый близкий пример, который у меня есть:

Это полезно, но не совсем верно (по крайней мере, это вызывает у меня ошибки с сообщением «неверный плагин»). Я не уверен, как его адаптировать, чтобы на странице списка групп я мог получать владельцев для каждой группы.

Не уверен, как именно вы пытались использовать пример плагина, но у меня он успешно работал на тестовом экземпляре при использовании структуры файлов и кода, который я опубликовал в вашей другой теме.

is_group_owner используется в контексте просмотра групп текущим пользователем.

Вы можете получить информацию о владельце через AJAX-запрос, но, насколько мне известно, это нужно делать для каждой группы в списке отдельно, что может привести к большому количеству запросов. В целом, по-моему, реализовать это таким способом будет сложно. В любом случае, если вы хотите поэкспериментировать, вы можете попробовать следующий фрагмент кода для доказательства концепции в теме. Просто замените GROUP_NAME на название одной из ваших групп. (РЕДАКТИРОВАНО: Вот также компонент темы с примером того, как можно использовать AJAX-запрос: discourse-featured-topics/common/head_tag.html at master · awesomerobot/discourse-featured-topics · GitHub)

<script type="text/discourse-plugin" version="0.8.40">
  const { ajax } = require("discourse/lib/ajax");
  ajax(`/groups/GROUP_NAME/members.json`).then(response => {
    console.log(response.owners.map(owner => owner.username))
  });
</script>

Сказав всё это, скажу, что использование плагина — безусловно самое простое и чистое решение.