Процесс создания плагинов для Redmine очень слабо документирован. Задача данной статьи отчасти восполнить этот пробел, рассказав про успешный опыт создания небольшого, но полезного плагина. Важное примечание. Redmine написан на Ruby on Rails, вам нужно быть к этому готовым, если вы собрались делать свой плагин :)
Исходная задача
Наша компания использует Redmine в качестве основного таск-трекера. Не буду рассматривать его плюсы и минусы, остановлюсь лишь на количестве писем, которые он шлет при любом изменении задач. В этом «шуме» иногда теряются новые задачи или важные комментарии.
Разработчики, конечно, предусмотрели ряд настроек на этот счет, но они довольно скудны. Хочется иметь возможность настроить уведомления на конкретные изменения.
Особенно напрягали уведомления на смену статуса задачи на «Задача закрыта». Мне, как разработчику, они не важны. Если по задаче есть доработки, то задаче снова присваивается статус «Новая», пишется какой-то комментарий, а я получаю уведомление и приступаю к ее решению.
Можно настроить фильтр в почте на такие письма (скажете вы), но гораздо интереснее было написать свой плагин, который позволит регулировать эти уведомления всем участникам процесса (исполнителям, авторам, наблюдателям).
Итак, задача: создать плагин, добавляющий в аккаунт пользователя настройку «Не извещать меня, когда задача закрыта».
Описание решения
Создание шаблона под плагин я опущу, это подробно описано в соответствующем разделе на redmine.org.
Добавим галочку, по аналогии с «Не извещать об изменениях, которые я сделал сам». Для этого просто скопируем шаблон appviewsusers_mail_notifications.html.erb в свой плагин и допишем требуемый html код.
Это не сильно правильно, но стандартный хук на форму пользователя :view_users_form, выводит чекбокс не в том месте, где хотелось. Redmine с каждой новой версией поддерживает все больше и больше хуков, но их всегда будет недостаточно и данный случай не исключение.
Далее «пропатчим» 3 метода, это создание и редактирование пользователя админом и редактирование на странице аккаунта. На эти методы тоже нет хуков, поэтому на помощь пришли «хуки из коробки»: alias_method и alias_method_chain. Логика их работы понятна из названия, связать методы и связать методы в цепочку.
За страницу аккаунта отвечает контроллер my_controller, метод account. Пропатчим его, создав файл в поддиректории плагина libpatches my_controller_patch.rb
module Patches
module MyControllerPatch
def self.included(base)
# наследуем родные методы
base.extend(ClassMethods)
# расширяем класс своими методами
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
# соединяем методы в цепочку
alias_method_chain :account, :ext
end
end
module ClassMethods
end
module InstanceMethods
# новый метод с расширением ext
def account_with_ext
if request.post?
# определяем отмечен ли чекбокс и добавляем значение в конфиг пользователя
User.current.pref[:no_self_notified_closed] = (params[:no_self_notified_closed] == '1')
end
# выполняем базовый метод account
account_without_ext
end
end
end
end
Создание и редактирование админом, аналогично.
Далее нужно считывать выставленное значение при формировании списка пользователей на рассылку уведомления, за это отвечает модель issue, метод recipients и watcher_recipients, копируем их в libpatches issue_patch.rb и изменяем под себя.
module Patches
module IssuePatch
def self.included(base)
…
base.class_eval do
unloadable
# переопределяем базовые методы своими
alias_method :recipients, :recipients_ext
alias_method :watcher_recipients, :watcher_recipients_ext
end
end
…
module InstanceMethods
# автор задачи и исполнители
def recipients_ext
# получаем иформацию о текущем статусе задачи
@status = IssueStatus.find_by_id(self.status_id)
notified = project.notified_users
# все что требует это добавить свою дополнительную проверку (метод allow_notify_closed)
notified << author if author && author.active? && author.notify_about?(self) && allow_notify_closed?(author)
if assigned_to
if assigned_to.is_a?(Group)
notified += assigned_to.users.select { |u| u.active? && u.notify_about?(self) && allow_notify_closed?(u) }
else
notified << assigned_to if assigned_to.active? && assigned_to.notify_about?(self) && allow_notify_closed?(assigned_to)
end
end
notified.uniq!
notified.reject! { |user| !visible?(user) }
notified.collect(&:mail)
end
# наблюдатели
def watcher_recipients_ext
notified = watcher_users.active
notified.reject! { |user| user.mail_notification == 'none' || allow_notify_closed?(user) === false }
if respond_to?(:visible?)
notified.reject! { |user| !visible?(user) }
end
notified.collect(&:mail).compact
end
private
# добавим свой метод, для проверки значения нашего чекбокса и свойства у статуса
def allow_notify_closed?(user)
(user.pref[:no_self_notified_closed] && @status.is_closed?) ? false : true
end
end
end
end
И осталось самое главное, подключить наши патчи. В корне плагина файл init.rb, дописываем:
# dispatcher позволяем расширить базовые классы нашими патчами
require 'dispatcher'
Dispatcher.to_prepare do
MyController.send(:include, Patches::MyControllerPatch)
UsersController.send(:include, Patches::UsersControllerPatch)
Issue.send(:include, Patches::IssuePatch)
end
Устанавливаем плагин в папку /vendor/plugins/ и перезапускаем redmine. Все, теперь можно управлять уведомлениями и не получать ненужные письма. Таким образом, вы можете изменить поведения любого метода в Redmine и написать свои плагины, автоматизирующие и облегчающие работу.
Ссылка на исходники https://github.com/parshukovvv/redmine_notice
Автор: parshukovvv