Статьи

Как создать расширение Trello Chrome — Аутентификация API

В SitePoint мы широко используем Trello. Конечно, он имеет свои причуды и может использовать одно или два улучшения в различных областях, но по большей части он революционизировал совместный опыт не только сотрудников, но также авторов и их редакторов.

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

Давайте сделаем расширение Chrome, которое может сделать это для нас! Если вы спешите и просто хотите увидеть конечный результат, посмотрите репозиторий Github для окончательной версии кода этого урока.

Создание расширения Chrome

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

Бутстрапирование

Я буду использовать мое верное хранилище ChromeSkel — скелетное расширение, которое я создал давно, чтобы упростить начало работы с Chrome Extension. Для справки, если вы хотите увидеть другие учебники по расширению Chrome, которые я написал в прошлом, смотрите здесь и здесь .

Начнем с клонирования репо в любую папку.

git clone https://github.com/Swader/ChromeSkel_a.git 

Чтобы увидеть, работает ли он, загрузите его в Chrome. Перейдите на вкладку расширений и нажмите «Загрузить распакованное расширение». Если опция отсутствует, убедитесь, что вы отметили флажок «Режим разработчика» в правом верхнем углу.

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

01

Аутентификация

В то время как мы могли бы просто собирать данные на экране с помощью расширения Chrome и анализировать это, Trello иногда оказывался ненадежным и, как правило, приводил к сбоям на густонаселенных платах. Вот почему мы будем использовать только интеграцию расширения Chrome с доменом trello.com для создания новых опций контекстного меню в списках (опция «Экспорт карт»), и мы будем выполнять всю логику на фоновой странице, выбирая данные через API.

Ключ и Секрет

Чтобы создать ключ приложения для Trello, перейдите по адресу https://trello.com/1/appKey/generate при входе в систему. Это даст вам ключ и секрет, которые вы можете использовать в своей учетной записи. В оставшейся части этого учебного пособия рассмотрите {{KEY}} в качестве этого ключа и замените содержимое соответствующим образом.

Когда у вас есть ключ, в key.js scripts создайте файл key.js :

 // key.js var APP_KEY = '{{KEY}}'; 

Пока вы это делаете, вы можете удалять fragments и папки с fancy-settings . Нам они не понадобятся.

Рабочий процесс и манифест

Идея рабочего процесса расширения заключается в следующем:

  • данный пользователь открывает доску Trello
  • проверить, разрешил ли указанный пользователь добавочный номер использовать свою учетную запись Trello
  • если да, продолжайте
  • если нет, откройте страницу настроек с кнопкой авторизации, которая позволяет им завершить процедуру
  • После авторизации закройте страницу настроек автоматически и оставьте добавочный номер авторизованным.

Чтобы расширение автоматически открывало новую вкладку с некоторым содержимым, мы должны пометить это содержимое как «доступный через Интернет ресурс» .

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

 { "name": "Trello Helper", "version": "0.1", "manifest_version" : 2, "description": "Trello Helper adds some much needed functionality to Trello. The current version focuses on exporting card information from lists.", "background" : { "page" : "background.html", "persistent": false }, "page_action" : { "default_icon": { "19": "icons/19.png", "38": "icons/38.png" } }, "content_scripts": [ { "matches": ["https://trello.com/b/*"], "js": [ "lib/jquery-2.1.1.min.js", "scripts/main.js" ], "run_at": "document_idle" } ], "permissions": [ "tabs" ], "icons": { "16": "icons/16.png", "48": "icons/48.png", "128": "icons/128.png" }, "web_accessible_resources": [ "settings/index.html" ], "options_page": "settings/index.html" } 

Большая часть этого должна быть знакомой. Мы устанавливаем версию, даем некоторые метаданные, определяем значки и объявляем страницу события , загружаем некоторые необходимые сценарии содержимого (нам нужен jQuery для клиентской библиотеки Trello JS ) и, наконец, определяем «web_accessible_resources», чтобы мы могли использовать страницу настроек, которую мы будем использовать строить Мы также ограничиваем влияние расширения на https://trello.com/b/* , то есть только URL-адреса форума.

Настройки и авторизация

Чтобы создать нашу страницу настроек, мы пишем простую страницу HTML. В демонстрационных целях я буду в этом случае очень прост. Мы будем использовать Foundation для стилизации (прямо сейчас, только для кнопок, но мы будем работать над улучшением страницы настроек в будущих публикациях), поэтому загрузите пакет базовых компонентов Foundation и разархивируйте его содержимое в /settings , чтобы index.html попадает в эту папку. У вас должна быть такая структура папок:

02

Если у вас есть дополнительные папки, которые не видны на моем скриншоте, удалите их. Создайте файл settings/js/settings.js , пока оставьте его пустым.

Хорошо, давайте приступим к делу. Таким образом, предполагается, что пользователь попадает на эту страницу, либо переходя к «Параметры» на вкладке «Расширения», либо пытаясь использовать расширение, когда его не аутентифицируют. Давайте создадим довольно простую HTML-страницу с двумя элементами div — одну для проверки подлинности пользователя с помощью кнопки «Выйти», а другую — для проверки подлинности, когда он еще не прошел проверку подлинности и ему необходимо нажать кнопку «Авторизовать». Замените содержимое index.html следующим:

 <!doctype html> <html class="no-js" lang="en"> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>Trello Helper Settings</title> <link rel="stylesheet" href="css/foundation.css"/> <script src="js/vendor/modernizr.js"></script> </head> <body> <div class="row"> <div class="large-12 columns"> <h1>Trello Helper Settings</h1> </div> </div> <div class="row"> <div class="large-12 columns"> <div class="panel" id="trello_helper_loggedout" style="display: none"> <p>To get going, you'll need to authorize the extension to use your Trello account.</p> <p>Do it by clicking the big Authorize button below.</p> <a href="#" class="medium success button" id="trello_helper_login">Authorize</a><br/> </div> <div class="panel" id="trello_helper_loggedin" style="display: none"> <p>You are already authorized. If something doesn't work, try logging out using the button below, and logging back in.</p> <a href="#" class="medium success button" id="trello_helper_logout">Log out</a><br/> </div> </div> </div> <script src="../scripts/key.js"></script> <script src="js/vendor/jquery.js"></script> <script src="js/settings.js"></script> </body> </html> 

У нас есть два элемента div, кнопка входа и выхода, и мы подключаем JS, который нам понадобится. В этом случае мы используем включенный по умолчанию jQuery, но на самом деле не имеет значения, если вы решите использовать свой собственный загруженный файл в другом месте проекта, в случае, если вы выбрали более современный, как я (подробнее на что позже).

Теперь давайте добавим немного логики. Откройте settings.js и предоставьте ему следующее содержимое:

 function init() { // Message and button containers var lout = $("#trello_helper_loggedout"); var lin = $("#trello_helper_loggedin"); // Log in button $("#trello_helper_login").click(function () { }); // Log out button $("#trello_helper_logout").click(function () { }); if (!localStorage.trello_token) { $(lout).show(); $(lin).hide(); } else { $(lout).hide(); $(lin).show(); } } $(document).ready(init); 

Читая документы , мы можем узнать, что trello_token будет существовать в localStorage когда клиентское приложение будет аутентифицировано. Это означает, что мы можем использовать его как индикатор того, когда показывать каждый из наших элементов. В функции init мы берем div, добавляем обработчики нажатия на кнопки (там пока нет логики) и, наконец, мы скрываем соответствующий div в соответствии с trello_token .

Например, когда пользователь проходит проверку подлинности, он получает такой экран:

03

Давайте сейчас получим клиент Trello JS.
Документация Trello на самом деле не написана с учетом расширений Chrome, и рекомендует подключать key к URL при извлечении клиентской библиотеки JS из их домена, например так:

 <script src="https://api.trello.com/1/client.js?key=substitutewithyourapplicationkey"></script> 

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

 https://api.trello.com/1/client.js 

Сохраните содержимое этого файла в lib/trello_client.js , затем убедитесь, что наша страница настроек загружает его, добавив его в раздел сценариев рядом с конечным <body> , например:

 <script src="js/vendor/jquery.js"></script> <script src="../lib/trello_client.js"></script> <script src="js/settings.js"></script> 

Это обеспечит доступность объекта Trello в нашем JavaScript, что позволит нам использовать его методы . Давайте сначала обработаем выход из системы. Измените обработчик нажатия кнопки выхода из системы следующим образом:

 $("#trello_helper_logout").click(function () { Trello.deauthorize(); location.reload(); }); 

Это все, что нужно, чтобы деавторизовать с Trello. Мы вызываем метод и перезагружаем страницу, на которой мы находимся (то есть экран настроек).

Теперь давайте обработаем вход в систему, что немного сложнее.

 // Log in button $("#trello_helper_login").click(function () { Trello.setKey(APP_KEY); Trello.authorize( { name: "Trello Helper Extension", type: "redirect", expiration: "never", interactive: true, scope: {read: true, write: false}, success: function () { // Can't do nothing, we've left the page }, error: function () { alert("Failed to authorize with Trello.") } }); }); 

Следуя логике онлайновых документов, мы видим, что у объекта Trello есть метод setKey , который мы удачно используем для его установки. Затем мы вызываем в действие метод authorize . Согласно документации, использование popup типа вместо redirect потребует от пользователя ручного вставления секретного ключа в приложение при его получении, что мы не ищем. Однако, если мы используем перенаправление, страница будет перенаправлена ​​на аутентификацию и вернется обратно после завершения. interactive поле, если установлено значение false, отменяет как всплывающее окно, так и перенаправление, и вместо этого проверяет только, существует ли значение localStorage.trello_token . Согласно документам, нам нужно сначала вызвать обычную авторизацию с перенаправлением, а затем, после возврата на страницу настроек, нам нужно вызвать его снова, но с интерактивным значением false, что заставит его получить токен предыдущего перенаправления. при условии. Это все немного запутанно, но это работает.

Есть и другая проблема. Если мы вызываем неинтерактивную authorize сразу после открытия страницы настроек, то мы вызовем ошибку на странице, потому что перенаправление после авторизации еще не произошло. В качестве альтернативы можно добавить еще одну кнопку «Подтвердить» или что-то подобное на нашей странице настроек, которая появляется после перенаправления из Trello обратно на нашу страницу настроек, позволяя пользователю инициировать неинтерактивную авторизацию вручную. Это похоже на кошмар UX. В итоге я выбрал третье решение.

Сохраните следующий код в lib/hashSearch.js .

 /* As found on: http://stackoverflow.com/questions/3729150/retrieve-specific-hash-tags-value-from-url */ var HashSearch = new function () { var params; this.set = function (key, value) { params[key] = value; this.push(); }; this.remove = function (key, value) { delete params[key]; this.push(); }; this.get = function (key, value) { return params[key]; }; this.keyExists = function (key) { return params.hasOwnProperty(key); }; this.push= function () { var hashBuilder = [], key, value; for(key in params) if (params.hasOwnProperty(key)) { key = escape(key), value = escape(params[key]); // escape(undefined) == "undefined" hashBuilder.push(key + ( (value !== "undefined") ? '=' + value : "" )); } window.location.hash = hashBuilder.join("&"); }; (this.load = function () { params = {} var hashStr = window.location.hash, hashArray, keyVal hashStr = hashStr.substring(1, hashStr.length); hashArray = hashStr.split('&'); for(var i = 0; i < hashArray.length; i++) { keyVal = hashArray[i].split('='); params[unescape(keyVal[0])] = (typeof keyVal[1] != "undefined") ? unescape(keyVal[1]) : keyVal[1]; } })(); } 

Как видно из ответа StackOverflow , эта небольшая утилита помогает нам получить значение определенного хэша из URL.

Когда вы авторизуетесь с помощью Trello через режим redirect , он будет перенаправлен обратно на страницу, с которой пришел, но с токеном в URL. Этот токен будет токеном аутентификации, который нужен клиенту Trello JS. Следовательно, само собой разумеется, что если мы сможем обнаружить присутствие этого токена в URL, мы можем заключить, что имеем дело с перенаправлением из Trello и, таким образом, можем автоматически и безопасно запускать неинтерактивный протокол authorize .

После добавления hashSearch на страницу настроек вот так …

 <script src="../scripts/key.js"></script> <script src="js/vendor/jquery.js"></script> <script src="../lib/trello_client.js"></script> <script src="../lib/hashSearch.js"></script> <script src="js/settings.js"></script> 

… Файл settings.js должен, в конце концов, выглядеть так:

 function init() { // Check if page load is a redirect back from the auth procedure if (HashSearch.keyExists('token')) { Trello.authorize( { name: "Trello Helper Extension", expiration: "never", interactive: false, scope: {read: true, write: false}, success: function () {}, error: function () { alert("Failed to authorize with Trello.") } }); } // Message and button containers var lout = $("#trello_helper_loggedout"); var lin = $("#trello_helper_loggedin"); // Log in button $("#trello_helper_login").click(function () { Trello.setKey(APP_KEY); Trello.authorize( { name: "Trello Helper Extension", type: "redirect", expiration: "never", interactive: true, scope: {read: true, write: false}, success: function () { // Can't do nothing, we've left the page }, error: function () { alert("Failed to authorize with Trello.") } }); }); // Log out button $("#trello_helper_logout").click(function () { Trello.deauthorize(); location.reload(); }); if (!localStorage.trello_token) { $(lout).show(); $(lin).hide(); } else { $(lout).hide(); $(lin).show(); } } $(document).ready(init); 

Теперь вы можете попробовать расширение. Загрузите вкладку расширений, нажмите на ссылку «Параметры» и проверьте аутентификацию и выход из системы. Все должно работать нормально.

Вывод

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

В следующей части мы построим всю логику за расширением и завершим вещи.