Plugin-Tutorial
перевод руководства по созданию плагинов для Redmine
руководство по созданию плагинов Redmine
данное руководство рассчитано на Redmine 2.x. Руководство по созданию плагинов для Redmine 1.xздесь. Данное руководство предполагает что вы знакомы Ruby on Rails framework.
Создание новых плагинов
Рекомендуется установить переменную окружения RAILS_ENV используя команду ниже
$ export RAILS_ENV="production"
в Windows
$ export RAILS_ENV=production
Создать новый плагин вы можете используя генератор плагинов Redmine. Генератор плагинов Redmine имеет следующий синтаксис
ruby script/rails generate redmine_plugin <plugin_name>.
Итак откройте командную строку и перейдите в каталог redmine, затем выполните следующую команду:
$ ruby script/rails generate redmine_plugin Polls create plugins/polls/app create plugins/polls/app/controllers create plugins/polls/app/helpers create plugins/polls/app/models create plugins/polls/app/views create plugins/polls/db/migrate create plugins/polls/lib/tasks create plugins/polls/assets/images create plugins/polls/assets/javascripts create plugins/polls/assets/stylesheets create plugins/polls/config/locales create plugins/polls/test create plugins/polls/README.rdoc create plugins/polls/init.rb create plugins/polls/config/routes.rb create plugins/polls/config/locales/en.yml create plugins/polls/test/test_helper.rb
Данная команда создала скелет вашего плагина в папке plugins/pools. Отредактируйте файл plugins/pools/init.rb и внесите туда необходимую информацию о плагине (название, Автор, описание, и версия)
Redmine::Plugin.register :polls do name 'Polls plugin' author 'John Smith' description 'A plugin for managing polls' version '0.0.1' end
Перезапустите приложение и зайдите в браузере на страницу (http://localhost:3000/admin/plugins) После входа под профилем админа вы сможете увидеть новый плагин в списке плагинов
Примечание: любые изменения init.rb файл плагина требует перезапуска приложения, поскольку оно не перезагружает init.rb после каждого запроса на каждый запрос.
Примечание: любые изменения init.rb файл плагина требует перезапуска приложения, поскольку оно не перезагружает init.rb после каждого запроса на каждый запрос.
Генерация модели
Сейчас плагин не может сохранять никакую информацию. Давайте создадим простую модель опроса(Poll) для нашего плагина. Для создания модели используйте следующий синтаксис:
ruby script/rails generate redmine_plugin_model <plugin_name> <model_name> [field[:type][:index] field[:type][:index] ...]
выполним команду в командной строке
$ ruby script/rails generate redmine_plugin_model polls poll question:string yes:integer no:integer create plugins/polls/app/models/poll.rb create plugins/polls/test/unit/poll_test.rb create plugins/polls/db/migrate/001_create_polls.rb
Это действие создаст модель Poll и соответствующий файл миграции file 001_create_polls.rb в plugins/polls/db/migrate:
class CreatePolls < ActiveRecord::Migration def change create_table :polls do |t| t.string :question t.integer :yes, :default => 0 t.integer :no, :default => 0 end end end
Вы можете настроить ваш файл миграции (те. значения по умолчанию...) затем перенести базу данных с помощью следующей команды(прогнать миграцию):
$ rake redmine:plugins:migrate Migrating polls (Polls plugin)... == CreatePolls: migrating ==================================================== -- create_table(:polls) -> 0.0410s == CreatePolls: migrated (0.0420s) ===========================================
Обратите внимание, что каждый модуль имеет свой собственный набор миграций.
Давайте добавим несколько опросов в консоли, так что нам было с чем работать. Консоль, где вы можете в интерактивном режиме работы и изучить Redmine среды и является очень информативной, чтобы поиграть. Но сейчас нам просто необходимо создать два Poll объекта
ruby script/rails console [rails 3] rails console >> Poll.create(:question => "Can you see this poll") >> Poll.create(:question => "And can you see this other poll") >> exit
Отредактируйте plugins/polls/app/models/poll.rb добавьте метод vote который будет вызываться из нашего контролера:
class Poll < ActiveRecord::Base def vote(answer) increment(answer == 'yes' ? :yes : :no) end end
Генерация контролера
Сейчас плагин ничего не делает. Поэтому давайте создадим контроллер для него. Мы будем использовать генератор контролера для плагинов redmine. Со следующим синтаксисом:
ruby script/rails generate redmine_plugin_controller <plugin_name> <controller_name> [<actions>]
Выполните эту команду в консоле
$ ruby script/rails generate redmine_plugin_controller Polls polls index vote create plugins/polls/app/controllers/polls_controller.rb create plugins/polls/app/helpers/polls_helper.rb create plugins/polls/test/functional/polls_controller_test.rb create plugins/polls/app/views/polls/index.html.erb create plugins/polls/app/views/polls/vote.html.erb
Это создаст контролер с двумя методами(actions)(#index и #vote). Отредактируйте файл plugins/polls/app/controllers/polls_controller.rb и внесите в два этих метода код необходимый для их работы
class PollsController 'index' end end
Затем отредактируйте plugins/polls/app/views/polls/index.html.erb, который будет отображать существующие опросы:
<h2>Polls</h2> <% @polls.each do |poll| %> <p> <%= poll.question %>? <%= link_to 'Yes', { :action => 'vote', :id => poll[:id], :answer => 'yes' }, :method => :post %> (<%= poll.yes %>) / <%= link_to 'No', { :action => 'vote', :id => poll[:id], :answer => 'no' }, :method => :post %> (<%= poll.no %>) </p> <% end %>
Вы можете удалить плагины/polls/app/views/polls/vote.html.erb поскольку визуализация данного файла выполнятся не будет.
Добавление Роутинга(маршруты)
Redmine не поддерживает подстановки по умолчанию маршрут (':controller/:action/:id'). Плагины должны декларировать маршруты, по которым они нуждаются в файле config/routes.rb. Теперь отредактируйте plugins/polls/config/routes.rb и добавьте в него 2 маршрута для двух действий
get 'polls', :to => 'polls#index' post 'post/:id/vote', :to => 'polls#vote'
вы можете найти больше информации о Роутинге в Rails здесь http://guides.rubyonrails.org/routing.htmlТеперь перезапустите ваше приложение и зайдите в браузере на страницу http://localhost:3000/polls. Вы должны увидеть 2 опроса и сможете проголосовать:
интернационализация
Перевод файлы должны быть сохранены в config/locales, например. plugins/polls/config/locales/.
Добавление пункта меню принадлежащего плагину
Наш контроллер работает нормально, но пользователи должны знать url, чтобы увидеть опросы. С помощью Redmine plugin API, вы можете расширить стандартные меню(добавить в них свой пункт меню). Поэтому давайте добавим новый элемент в меню приложения.
Redmine::Plugin.register :redmine_polls do [...] menu :application_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls' end
Синтаксис:
menu(menu_name, item_name, url, options={})
Существует пять меню, которые можно расширить:
- :top_menu - в верхнем левом меню
- :account_menu - в верхнем правом рядом в ссылками войти зарегистрировать
- :application_menu - главное меню отображается, когда пользователь находится не внутри проекта
- :project_menu - главное меню отображается, когда пользователь находится внутри проекта
- :admin_menu - меню отображается на странице администрирования (можете вставить после установки, прежде чем Plugins)
Доступные варианты:
- :param - параметр ключ, используемый для проекта id (по умолчанию :id)
- :if - Proc, которая вызывается перед отображением элемента, элемент отображается, только если она возвращает true,
- :caption - меню заголовка, который может содержать:
- локализованную строку Symbol (например :plugin_local_name)
- строку
- Proc, которые могут принять проект в качестве аргумента
- :before, :after - место где в меню должен быть вставлен элемент (например. :after => :activity)
- :first, :last - если установлено в true, то элемент будет встать в начало или в конец меню (например. :last => true)
- :html - hash с html параметрами, передаваемые link_to при отображении пункта меню
В нашем примере мы добавили элемент в меню приложения, которая не содержит элементов по умолчанию. Перезапустите redmine и перейдите http://localhost:3000
Теперь вы можете получить доступ к опросам, нажав на вкладке Polls с экрана приветствия.
Расширение меню проекта
Теперь, давайте рассмотрим, случай когда необходимо чтобы опросы задавались на уровне проекта (даже если это не так, в нашем примере).Мы хотели бы добавить Вкладку Polls в меню проекта, а не в меню приложения Откройте init.rb и замените строку, которую мы добавляли ранее ( menu :application_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls') на следующие две
Redmine::Plugin.register :redmine_polls do [...] permission :polls, { :polls => [:index, :vote] }, :public => true menu :project_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls', :after => :activity, :param => :project_id end
Вторая строка добавляет наши опросы вкладки в меню проекта, сразу после вкладки activity. Первая строка необходима и заявляет, что наши два метода из PollsController являются публичными. Мы вернемся позже, чтобы объяснить это более подробно. Перезапустить приложение и перейдите к одному из ваших проектов:
Если вы щелкните на вкладке Polls(в 3-й позиции), то вы должны заметить, что меню проекта не отображается. Чтобы сделать проект меню видимой, вы должны инициализировать в контроллере инстансную переменную проекта (@project)
Для этого отредактируйте PollsController следующим образом
def index @project = Project.find(params[:project_id]) @polls = Poll.find(:all) # @project.polls end
id проекта доступна в param[:project_id] Теперь вы должны увидеть меню проекта находясь на вкладке Polls
Добавление новых прав
Сейчас любой желающий может проголосовать и посмотреть опросы. Давайте сделаем ее более гибкую настройку прав Мы собираемся создать 2 разрешения : одно для просмотра опросы и другая для голосования. Эти разрешения не публичные(опция :public => true удаляется). отредактируйте plugins/polls/init.rb и замените строчку с permission на две следующих
permission :view_polls, :polls => :index permission :vote_polls, :polls => :vote
Перезапустите redmine и перейдите http://localhost:3000/roles/permissions: Теперь вы настраивать эти два разрешения для существующих ролей. Конечно, необходимо добавить код в PollsController который сделает эту защиту фактической в соответствии привилегиями текущего пользователя. Для этого нам всего лишь нужно добавить :authorize filter и сделать получение инстансной переменной @project возможной только после отработки данного фильтра Вот как это будет выглядеть для метода #index.
class PollsController :index [...] def index @polls = Poll.find(:all) # @project.polls end [...] private def find_project # @project variable must be set before calling the authorize filter @project = Project.find(params[:project_id]) end end
Для метода vote данная проверка прав может быть сделана по аналогии После этого просмотр опросов и возможность голосовать будет доступна только админам и пользователям для ролей которых выставлены соответствующие разрешения
Если вы хотите ваши разрешения в на различных языках, вам нужно добавить необходимые текстовые метки в файле языка. Просто создайте файл соответствующий нужному языку *.yml (например. en.yml для английского) в папке plugins/polls/config/locales и внесите туда метки и перевод для них например как указано ниже
"en": permission_view_polls: View Polls permission_vote_polls: Vote Polls
В этом примере создается файл именем en.yml, но для всех остальных языков можно создать файлы аналогично. Как вы можете видеть на примере выше, метки соответствуют символам :view_polls и :vote_polls с дополнительным permission_.
Перезапустите redmine и укажите необходимые права
Создание модуля проекта
Теперь функции опроса доступны для всех ваших проектов.Но вы хотите иметь возможность включать ее только для некоторых проектов Итак, давайте создадим 'Polls' модуль проекта. Это делается путем оборачивания получение разрешений методом #project_module.
Отредактируйте init.rb и измените декларацию permissions(прав)
project_module :polls do permission :view_polls, :polls => :index permission :vote_polls, :polls => :vote end
Перезапустите redmine и перейдите в настройки проекта Щелкнете не вкладке Modules. И вы сможете модуль Polls в списке модулей (выключенный по умолчанию) Теперь вы можете включать и выключать опросы для различных проектов
Улучшение внешнего вида проекта
Добавление стилей
Давайте начнем с добавления стилей для нашего плагина. Создайте файл с именем voting.css в каталоге plugins/polls/assets/stylesheets
a.vote { font-size: 120%; } a.vote.yes { color: green; } a.vote.no { color: red; }
При запуске приложения, файлы из файлопровода плагина (plugins/polls/assets) будут скопированы в public/plugin_assets/polls/ это необходимо чтобы сделать их доступными для вашего web-сервера. Поэтому любые изменения, таблицы стилей или javascripts в плагине требуют перезапуска Redmine. Используемые в стилях классы необходимо объявить в ссылках. для этого измените их в файле plugins/polls/app/views/polls/index.html.erb следующим образом
<%= link_to 'Yes', {:action => 'vote', :id => poll[:id], :answer => 'yes' }, :method => :post, :class => 'vote yes' %> (<%= poll.yes %>) <%= link_to 'No', {:action => 'vote', :id => poll[:id], :answer => 'no' }, :method => :post, :class => 'vote no' %> (<%= poll.no %>)
Затем добавьте следующие строки в конце index.html.erb так, что ваша Таблица стилей может попасть в head страницы по Redmine:
<% content_for :header_tags do %> <%= stylesheet_link_tag 'voting', :plugin => 'polls' %> <% end %>
Обратите внимание, что :plugin => 'polls' параметр требуется при вызове stylesheet_link_tag хелпера.
Скрипты могут быть включены в плагин представлений с использованием javascript_include_tag хелпера таким же образом.
Установка заголовка страницы
Вы можете задать title страницы внутри вашего представления с помощью html_title хелпера.
<% html_title "Polls" % >
Использование хуков(hooks)
Хуки в отображении
Хуки в отображениях в редмайне позволяют вставлять ваш контент в заранее определенные места в шаблонов. для примера посмотрите например код представленный по следующей ссылкеhttp://www.redmine.org/projects/redmine/repository/entry/tags/2.0.0/app/views/projects/show.html.erb#L52 вы можете увидеть два хука: первый имеет имя :view_projects_show_left и предназначен для вставки контента в левую часть шаблона и второй с именем :view_projects_show_right для вставки контента в правую часть шаблона.
Чтобы использовать один или несколько хуков в отображениях вы должны создать класс наследуемый от Redmine::Hook::ViewListener и реализующий методы хуков которые вы желаете использовать. Теперь чтобы выводить контент для определенных хуков на вкладке "обзор" в проектах вам вам необходимом подключить ваш класс в файле init.rb и реализовать методы с именами хуков которые хотите использовать.
Для нашего плагина создайте файл plugins/polls/lib/polls_hook_listener.rb и добавьте в него следующий код:
class PollsHookListener < Redmine::Hook::ViewListener def view_projects_show_left(context = {}) return content_tag("p", "Custom content added to the left") end def view_projects_show_right(context = {}) return content_tag("p", "Custom content added to the right") end end
Также добавьте строчку в конец файла plugins/polls/init.rb:
require_dependency 'polls_hook_listener'
Перезапустите Redmine и перейдите на вкладку "обзор" проекта. Где вы сможете увидеть две наших строчки слева и справа.
Вы также можете использовать хелпер render_on для отображения частичных шаблонов. В нашем плагине замените содержимое файла plugins/polls/lib/polls_hook_listener.rb следующим:
class PollsHookListener "polls/project_overview" end
Добавьте частичный шаблон в наш плагин для этого создайте файл app/views/polls/_project_overview.html.erb. Добавьте в него контент (Например "Это сообщение выведено с использованием хуков") который будет выведен в левой части вкладки "обзор" на странице проекта. Не забудьте перезапустить Redmine.
Хуки в контролерах
В работе
Создание настроек для вашего плагина
каждый плагин зарегистрированный в Redmine появляется на странице admin/plugins. Поддержка настроек осуществляется Settings controllerом. Данную фичу можно включить путем добавления метода "settings" в блок регистрирующий плагин в файле init.rb
Redmine::Plugin.register :redmine_polls do [ ... ] settings :default => {'empty' => true}, :partial => 'settings/poll_settings' end
Добавление этого метода приведет к двум вещам. Во первых в блоке описания плагина добавится ссылка "Configure". Переход по которой приведет к странице созданной из частичного шаблона settings/poll_settings на которой будет распологаться ваши настройки. Во вторых появится возможность сохранять эти настройки в модуле плагина. Настройки будут сохранятся в виде хеша имя которого основанного на названии вашего плагина. Доступ к этому хешу можно получить при помощи объекта Setting передав в качестве метода plugin_<plugin name>. Например для нашего примера доступ к хешу можно получить вызвав Setting.plugin_redmine_polls. Отображение которое будет загружено необходимо указать в параметре ключа :partial метода setting вызываемого при регистрации вашего плагина. Форма с настройками вашего плагина будет отображена внутри основного шаблона Redmine содержащего тег формы и кнопку для применения настроек. Параметры вашего плагина могут быть отображены при помощи стандартных элементов HTML форм.
Предупреждение Если два плагина будут иметь одинаковые имя переданное в ключе :partial то настройки одного плагина перепишут настройки другого. По этому старайтесь придумать такие имена которые будут уникальны.
Предупреждение Если два плагина будут иметь одинаковые имя переданное в ключе :partial то настройки одного плагина перепишут настройки другого. По этому старайтесь придумать такие имена которые будут уникальны.
При формы с настройками, settings_controller будет принимать в качестве параметра хеш сформированный из вашей формы путем ее сериализации и сохранять в таком виде непосредственно в Setting.plugin_redmine_polls. Каждый раз при отображении страницы с вашими настройками значение Setting.plugin_redmine_polls будет содержать последние сохраненные настройки.
<table> <tbody> <tr> <th>Notification Default Address</th> <td><input type="text" id="settings_notification_default" value="<%= settings['notification_default'] %>" name="settings[notification_default]" > </tr> </tbody> </table>
В этом примере например для создания элементов формы конфигурации не используются Rails хелперы для форм. Это сделано по тому что мы не можем принимать параметров вида @settings только хеш. Form helpers будут пытаться получить доступ к атрибутам модели которой не существует. Например обращение к @settings.notification_default окончится неудачей так как его не существует и для обращения к данной опции следует использовать Setting.plugin_redmine_polls['notification_default'].
Наконец при указании ключа :default в методе settings при регистрации плагина можно будет указать значение которое будет возвращено Setting.plugin_redmine_polls в случаее если настройки еще не были установлены.
Тестирование вашего плагина
test/test_helper.rb
Вот содержание моего хелпер файла для тестов
require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper')
Пример теста
файл polls_controller_test.rb содержит следующий код:
require File.expand_path('../../test_helper', __FILE__) class PollsControllerTest 1 assert_response :success assert_template 'index' end end
Выполнение теста
Инициализируйте базу данных " test", если это необходимо:
$ rake db:drop db:create db:migrate redmine:plugins:migrate redmine:load_default_data RAILS_ENV=test
выполните polls_controller_test.rb
Тестирование с учетом привилегий
Если ваш плагин требует наличие пользователя в проекте, то добавьте следующую строку в начале вашего функционального теста:
def test_index @request.session[:user_id] = 2 ... end
Если ваш плагин требуется специальное разрешение, необходимо добавить еще роль пользователя, например, так (укажите id ролей, которые подходят для пользователя):
def test_index Role.find(1).add_permission! :my_permission ... end
Вы можете включить/отключить определенней модули следующим образом:
def test_index Project.find(1).enabled_module_names = [:mymodule] ... end
Комментариев нет:
Отправить комментарий