EasyRedmine compatibility

This commit is contained in:
Karel Pičman 2019-08-09 12:59:07 +02:00
parent bcfaf1c3e8
commit 5590a27c49
17 changed files with 379 additions and 236 deletions

View File

@ -21,7 +21,10 @@
source 'https://rubygems.org' source 'https://rubygems.org'
# In order to the plugin in Redmine < 4 (Rails < 5), comment out the following lines
# I don't know how to check Redmine or better Rails version here :-(
gem 'acts_as_list' gem 'acts_as_list'
gem 'activemodel-serializers-xml' gem 'activemodel-serializers-xml'
# Redmine extensions
unless %w(easyproject easy_gantt).any? { |plugin| Dir.exist?(File.expand_path("../../#{plugin}", __FILE__)) }
gem 'redmine_extensions', '~> 0.2.5'
end

40
after_init.rb Normal file
View File

@ -0,0 +1,40 @@
# encoding: utf-8
#
# Redmine plugin for Custom Workflows
#
# Copyright Anton Argirov
# Copyright Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require_dependency File.dirname(__FILE__) + '/lib/redmine_custom_workflows.rb'
ActiveSupport::Dependencies.autoload_paths << File.join(File.dirname(__FILE__), 'app')
def custom_workflows_init
# Administration menu extension
Redmine::MenuManager.map :admin_menu do |menu|
menu.push :custom_workflows, { controller: 'custom_workflows', action: 'index'},
caption: :label_custom_workflow_plural, html: { class: 'icon icon-custom-workflows'}
end
end
if Redmine::Plugin.installed?(:easy_extensions)
ActiveSupport.on_load(:easyproject, yield: true) do
custom_workflows_init
end
else
custom_workflows_init
end

View File

@ -0,0 +1,64 @@
/*
* Redmine plugin for Document Management System "Features"
*
* Copyright Anton Argirov
* Copyright Karel Pičman <karel.picman@kontron.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#tab-content-custom_workflows .disabled {
color: silver;
}
table.list.custom-workflows td {
vertical-align: middle;
}
table.list.custom-workflows td.description {
text-align: left;
width: 40%;
}
table.list.custom-workflows td.buttons {
white-space: normal;
width: 10%;
text-align: left;
}
table.list.custom-workflows tr.disabled {
color: silver;
}
#custom_workflow_description, #custom_workflow_name {
width: 98%;
}
.custom_workflow_script {
width: 98%;
font-size: 11px;
}
#custom_workflow_enabled_projects ul {
max-height: 200px;
overflow-y: auto;
}
/* Icons */
.icon-export { background-image: url(../images/export.png); }
.icon-import { background-image: url(../images/import.png); }
.icon-active { background-image: url(../images/active.png); }
.icon-inactive { background-image: url(../images/inactive.png); }
.icon-custom-workflows { background-image: url(../../../images/ticket_go.png); }

View File

@ -23,38 +23,43 @@ class CreateExampleWorkflow < ActiveRecord::Migration[4.2]
def up def up
CustomWorkflow.reset_column_information CustomWorkflow.reset_column_information
old = CustomWorkflow.where(:name => 'Duration/Done Ratio/Status correlation').first name = 'Duration/Done Ratio/Status correlation'
old = CustomWorkflow.where(name: name).first
old.destroy if old old.destroy if old
cw = CustomWorkflow.new
cw.name = name
cw.author = 'anton.argirov@gmail.com'
cw.description = %{
Set up a correlation between the start date, due date, done ratio and status of issues.
CustomWorkflow.create!(:name => 'Duration/Done Ratio/Status correlation', :author => 'anton.argirov@gmail.com', :description => <<EOD, :before_save => <<EOS) * If done ratio is changed to 100% and status is "In Process", status changes to "Resolved"
Set up a correlation between the start date, due date, done ratio and status of issues. * If status is "New", "Resolved" or "Feedback" and done ratio is changed to value less than 100%, status changes to "In process"
* If status is changed to "In process" and start date is not set, then it sets to current date
* If status is changed to "Resolved" and end date is not set, then it set to due date
* If done ratio is changed to 100% and status is "In Process", status changes to "Resolved" To use this script properly, turn off "Use current date as start date for new issues" option in the settings as this script already do it own way.
* If status is "New", "Resolved" or "Feedback" and done ratio is changed to value less than 100%, status changes to "In process" }
* If status is changed to "In process" and start date is not set, then it sets to current date cw.before_save = %{
* If status is changed to "Resolved" and end date is not set, then it set to due date if @issue.done_ratio_changed?
if (@issue.done_ratio == 100) && (@issue.status_id == 2)
To use this script properly, turn off "Use current date as start date for new issues" option in the settings as this script already do it own way. @issue.status_id = 3
EOD elsif [1,3,4].include?(@issue.status_id) && (@issue.done_ratio < 100)
if @issue.done_ratio_changed? @issue.status_id = 2
if @issue.done_ratio==100 && @issue.status_id==2 end
@issue.status_id=3
elsif [1,3,4].include?(@issue.status_id) && @issue.done_ratio<100
@issue.status_id=2
end end
end
if @issue.status_id_changed? if @issue.status_id_changed?
if @issue.status_id==2 if @issue.status_id == 2
@issue.start_date ||= Time.now @issue.start_date ||= Time.now
end end
if @issue.status_id==3 if @issue.status_id == 3
@issue.done_ratio = 100 @issue.done_ratio = 100
@issue.start_date ||= @issue.created_on @issue.start_date ||= @issue.created_on
@issue.due_date ||= Time.now @issue.due_date ||= Time.now
end end
end end
EOS }
cw.save!
end end
end end

21
init.rb
View File

@ -19,24 +19,25 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'redmine'
Redmine::Plugin.register :redmine_custom_workflows do Redmine::Plugin.register :redmine_custom_workflows do
if Redmine::Plugin.installed?(:easy_extensions)
name 'Easy Custom Workflow plugin'
url 'https://www.easyredmine.com'
author_url 'https://www.easyredmine.com'
else
name 'Redmine Custom Workflow plugin' name 'Redmine Custom Workflow plugin'
url 'https://www.redmine.org/plugins/custom-workflows'
author_url 'https://github.com/danmunn/redmine_custom_workflows/graphs/contributors'
end
author 'Anton Argirov/Karel Pičman' author 'Anton Argirov/Karel Pičman'
description 'Allows to create custom workflows for issues, defined in the plain Ruby language' description 'Allows to create custom workflows for objects, defined in the plain Ruby language'
version '1.0.1' version '1.0.1'
url 'http://www.redmine.org/plugins/custom-workflows'
requires_redmine version_or_higher: '4.0.0' requires_redmine version_or_higher: '4.0.0'
permission :manage_project_workflow, {}, :require => :member permission :manage_project_workflow, {}, :require => :member
end end
require_dependency File.dirname(__FILE__) + '/lib/redmine_custom_workflows.rb' unless Redmine::Plugin.installed?(:easy_extensions)
require_relative 'after_init'
# Administration menu extension
Redmine::MenuManager.map :admin_menu do |menu|
menu.push :custom_workflows, { controller: 'custom_workflows', action: 'index'},
caption: :label_custom_workflow_plural, html: { class: 'icon icon-workflows'}
end end

View File

@ -22,9 +22,20 @@
module RedmineCustomWorkflows module RedmineCustomWorkflows
class Hooks < Redmine::Hook::ViewListener class Hooks < Redmine::Hook::ViewListener
def view_layouts_base_html_head(context) def view_layouts_base_html_head(context)
stylesheet_link_tag :style, :plugin => 'redmine_custom_workflows' return if defined?(EasyExtensions)
"\n".html_safe + stylesheet_link_tag('custom_workflows.css', plugin: :redmine_custom_workflows)
end end
def easy_extensions_javascripts_hook(context={})
context[:template].require_asset('tab_override.js')
end
def easy_extensions_stylesheets_hook(context={})
context[:template].require_asset('custom_workflows.css')
end
end end
end end

View File

@ -24,7 +24,6 @@ module RedmineCustomWorkflows
module AttachmentPatch module AttachmentPatch
def self.included(base) def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do base.class_eval do
before_save :before_save_custom_workflows before_save :before_save_custom_workflows
after_save :after_save_custom_workflows after_save :after_save_custom_workflows
@ -33,8 +32,6 @@ module RedmineCustomWorkflows
end end
end end
module InstanceMethods
def before_save_custom_workflows def before_save_custom_workflows
@attachment = self @attachment = self
@saved_attributes = attributes.dup @saved_attributes = attributes.dup
@ -59,11 +56,9 @@ module RedmineCustomWorkflows
end end
end end
end
end end
end end
unless Attachment.include?(RedmineCustomWorkflows::Patches::AttachmentPatch) # Apply patch
Attachment.send(:include, RedmineCustomWorkflows::Patches::AttachmentPatch) RedmineExtensions::PatchManager.register_model_patch 'Attachment',
end 'RedmineCustomWorkflows::Patches::AttachmentPatch'

View File

@ -24,7 +24,6 @@ module RedmineCustomWorkflows
module GroupPatch module GroupPatch
def self.included(base) def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do base.class_eval do
before_save :before_save_custom_workflows before_save :before_save_custom_workflows
after_save :after_save_custom_workflows after_save :after_save_custom_workflows
@ -47,8 +46,6 @@ module RedmineCustomWorkflows
end end
end end
module InstanceMethods
def before_save_custom_workflows def before_save_custom_workflows
@group = self @group = self
@saved_attributes = attributes.dup @saved_attributes = attributes.dup
@ -73,11 +70,9 @@ module RedmineCustomWorkflows
end end
end end
end
end end
end end
unless Group.include?(RedmineCustomWorkflows::Patches::GroupPatch) # Apply patch
Group.send(:include, RedmineCustomWorkflows::Patches::GroupPatch) RedmineExtensions::PatchManager.register_model_patch 'Group',
end 'RedmineCustomWorkflows::Patches::GroupPatch'

View File

@ -24,7 +24,6 @@ module RedmineCustomWorkflows
module IssuePatch module IssuePatch
def self.included(base) def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do base.class_eval do
before_save :before_save_custom_workflows before_save :before_save_custom_workflows
after_save :after_save_custom_workflows after_save :after_save_custom_workflows
@ -49,8 +48,6 @@ module RedmineCustomWorkflows
end end
end end
module InstanceMethods
def validate_status def validate_status
return true unless @saved_attributes && @saved_attributes['status_id'] != status_id && return true unless @saved_attributes && @saved_attributes['status_id'] != status_id &&
!new_statuses_allowed_to(User.current, new_record?).collect(&:id).include?(status_id) !new_statuses_allowed_to(User.current, new_record?).collect(&:id).include?(status_id)
@ -87,11 +84,9 @@ module RedmineCustomWorkflows
end end
end end
end
end end
end end
unless Issue.include?(RedmineCustomWorkflows::Patches::IssuePatch) # Apply patch
Issue.send(:include, RedmineCustomWorkflows::Patches::IssuePatch) RedmineExtensions::PatchManager.register_model_patch 'Issue',
end 'RedmineCustomWorkflows::Patches::IssuePatch'

View File

@ -0,0 +1,54 @@
# encoding: utf-8
#
# Redmine plugin for Custom Workflows
#
# Copyright Anton Argirov
# Copyright Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module RedmineCustomWorkflows
module Patches
module MailerPatch
def self.deliver_custom_email(headers={})
user = headers.delete :user
headers[:to] = user.mail if user
text_body = headers.delete :text_body
html_body = headers.delete :html_body
template_name = headers.delete :template_name
template_params = headers.delete(:template_params) || {}
if text_body || html_body
mail headers do |format|
format.text { render :text => text_body } if text_body
format.html { render :text => html_body } if html_body
end
elsif template_name
template_params.each { |k,v| instance_variable_set("@#{k}", v) }
mail headers do |format|
format.text { render template_name }
format.html { render template_name } unless Setting.plain_text_mail?
end
else
raise 'Not :text_body, :html_body or :template_name specified'
end
end
end
end
end
RedmineExtensions::PatchManager.register_model_patch 'Mailer',
'RedmineCustomWorkflows::Patches::MailerPatch'

View File

@ -24,7 +24,6 @@ module RedmineCustomWorkflows
module ProjectPatch module ProjectPatch
def self.included(base) def self.included(base)
base.send :include, InstanceMethods
base.class_eval do base.class_eval do
has_and_belongs_to_many :custom_workflows has_and_belongs_to_many :custom_workflows
safe_attributes :custom_workflow_ids, :if => safe_attributes :custom_workflow_ids, :if =>
@ -48,8 +47,6 @@ module RedmineCustomWorkflows
end end
end end
module InstanceMethods
def before_save_custom_workflows def before_save_custom_workflows
@project = self @project = self
@saved_attributes = attributes.dup @saved_attributes = attributes.dup
@ -74,11 +71,9 @@ module RedmineCustomWorkflows
end end
end end
end
end end
end end
unless Project.include?(RedmineCustomWorkflows::Patches::ProjectPatch) # Apply patch
Project.send(:include, RedmineCustomWorkflows::Patches::ProjectPatch) RedmineExtensions::PatchManager.register_model_patch 'Project',
end 'RedmineCustomWorkflows::Patches::ProjectPatch'

View File

@ -34,4 +34,9 @@ module RedmineCustomWorkflows
end end
end end
ProjectsController.send :helper, RedmineCustomWorkflows::Patches::ProjectsHelperPatch if Redmine::Plugin.installed?(:easy_extensions)
RedmineExtensions::PatchManager.register_helper_patch 'ProjectsHelper',
'RedmineCustomWorkflows::Patches::ProjectsHelperPatch', prepend: true
else
ProjectsController.send :helper, RedmineCustomWorkflows::Patches::ProjectsHelperPatch
end

View File

@ -24,7 +24,6 @@ module RedmineCustomWorkflows
module TimeEntryPatch module TimeEntryPatch
def self.included(base) def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do base.class_eval do
before_save :before_save_custom_workflows before_save :before_save_custom_workflows
after_save :after_save_custom_workflows after_save :after_save_custom_workflows
@ -33,8 +32,6 @@ module RedmineCustomWorkflows
end end
end end
module InstanceMethods
def before_save_custom_workflows def before_save_custom_workflows
@time_entry = self @time_entry = self
@saved_attributes = attributes.dup @saved_attributes = attributes.dup
@ -59,11 +56,9 @@ module RedmineCustomWorkflows
end end
end end
end
end end
end end
unless TimeEntry.include?(RedmineCustomWorkflows::Patches::TimeEntryPatch) # Apply patch
TimeEntry.send(:include, RedmineCustomWorkflows::Patches::TimeEntryPatch) RedmineExtensions::PatchManager.register_model_patch 'TimeEntry',
end 'RedmineCustomWorkflows::Patches::TimeEntryPatch'

View File

@ -24,7 +24,6 @@ module RedmineCustomWorkflows
module UserPatch module UserPatch
def self.included(base) def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do base.class_eval do
before_save :before_save_custom_workflows before_save :before_save_custom_workflows
after_save :after_save_custom_workflows after_save :after_save_custom_workflows
@ -33,8 +32,6 @@ module RedmineCustomWorkflows
end end
end end
module InstanceMethods
def before_save_custom_workflows def before_save_custom_workflows
@user = self @user = self
@saved_attributes = attributes.dup @saved_attributes = attributes.dup
@ -59,11 +56,9 @@ module RedmineCustomWorkflows
end end
end end
end
end end
end end
unless User.include?(RedmineCustomWorkflows::Patches::UserPatch) # Apply patch
User.send(:include, RedmineCustomWorkflows::Patches::UserPatch) RedmineExtensions::PatchManager.register_model_patch 'User',
end 'RedmineCustomWorkflows::Patches::UserPatch'

View File

@ -24,7 +24,6 @@ module RedmineCustomWorkflows
module VersionPatch module VersionPatch
def self.included(base) def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do base.class_eval do
before_save :before_save_custom_workflows before_save :before_save_custom_workflows
after_save :after_save_custom_workflows after_save :after_save_custom_workflows
@ -33,8 +32,6 @@ module RedmineCustomWorkflows
end end
end end
module InstanceMethods
def before_save_custom_workflows def before_save_custom_workflows
@version = self @version = self
@saved_attributes = attributes.dup @saved_attributes = attributes.dup
@ -59,11 +56,9 @@ module RedmineCustomWorkflows
end end
end end
end
end end
end end
unless Version.include?(RedmineCustomWorkflows::Patches::VersionPatch) # Apply patch
Version.send(:include, RedmineCustomWorkflows::Patches::VersionPatch) RedmineExtensions::PatchManager.register_model_patch 'Version',
end 'RedmineCustomWorkflows::Patches::VersionPatch'

View File

@ -24,7 +24,6 @@ module RedmineCustomWorkflows
module WikiContentPatch module WikiContentPatch
def self.included(base) def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do base.class_eval do
before_save :before_save_custom_workflows before_save :before_save_custom_workflows
after_save :after_save_custom_workflows after_save :after_save_custom_workflows
@ -33,8 +32,6 @@ module RedmineCustomWorkflows
end end
end end
module InstanceMethods
def before_save_custom_workflows def before_save_custom_workflows
@content = self @content = self
@saved_attributes = attributes.dup @saved_attributes = attributes.dup
@ -59,11 +56,9 @@ module RedmineCustomWorkflows
end end
end end
end
end end
end end
unless WikiContent.include?(RedmineCustomWorkflows::Patches::WikiContentPatch) # Apply patch
WikiContent.send(:include, RedmineCustomWorkflows::Patches::WikiContentPatch) RedmineExtensions::PatchManager.register_model_patch 'WikiContent',
end 'RedmineCustomWorkflows::Patches::WikiContentPatch'

View File

@ -42,6 +42,6 @@ module RedmineCustomWorkflows
end end
end end
unless WikiPage.include?(RedmineCustomWorkflows::Patches::WikiPagePatch) # Apply patch
WikiPage.send(:include, RedmineCustomWorkflows::Patches::WikiPagePatch) RedmineExtensions::PatchManager.register_model_patch 'WikiPage',
end 'RedmineCustomWorkflows::Patches::WikiPagePatch'