Redmine 6.0.0 #350

This commit is contained in:
Karel Pičman 2024-11-20 12:19:12 +01:00
parent 03989743d7
commit 8a4218fa11
16 changed files with 74 additions and 79 deletions

View File

@ -83,7 +83,7 @@ jobs:
sudo apt-get install subversion
- name: Clone Redmine
# Get the latest stable Redmine
run: svn export http://svn.redmine.org/redmine/branches/5.1-stable/ /opt/redmine
run: svn export http://svn.redmine.org/redmine/branches/6.0-stable/ /opt/redmine
- name: Checkout code
uses: actions/checkout@v3
- name: Link the plugin

View File

@ -1,7 +1,7 @@
Changelog for Custom Workflows
==============================
2.1.3 *????-??-??*
3.0.0 *????-??-??*
------------------
2.1.2 *2024-06-28*

View File

@ -1,4 +1,4 @@
Custom Workflows plug-in 2.1.3 devel
Custom Workflows plug-in 3.0.0 devel
====================================
[![GitHub CI](https://github.com/anteo/redmine_custom_workflows/actions/workflows/rubyonrails.yml/badge.svg?branch=devel)](https://github.com/anteo/redmine_custom_workflows/actions/workflows/rubyonrails.yml)

View File

@ -25,7 +25,8 @@ 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-workflows workflows' }
caption: :label_custom_workflow_plural, icon: 'workflows',
html: { class: 'icon icon-workflows workflows' }
end
end

View File

@ -1,24 +0,0 @@
# frozen_string_literal: true
# Redmine plugin for Custom Workflows
#
# Anton Argirov, 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.
# Application record class
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end

View File

@ -40,7 +40,7 @@ class CustomWorkflowMailer < Mailer
format.html { render plain: html_body } if html_body.present? && !Setting.plain_text_mail?
end
elsif template_name
template_params.each { |k, v| instance_variable_set("@#{k}", v) }
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?

View File

@ -20,9 +20,9 @@
<% html_title l(:label_custom_workflow_plural) %>
<div class="contextual">
<%= link_to l(:label_custom_workflow_new), new_custom_workflow_path, class: 'icon icon-add' %>
<%= link_to sprite_icon('add', l(:label_custom_workflow_new)), new_custom_workflow_path, class: 'icon icon-add' %>
<%= actions_dropdown do %>
<%= link_to l(:label_custom_workflow_import), '#', class: 'icon icon-move',
<%= link_to sprite_icon('import', l(:label_custom_workflow_import)), '#', class: 'icon icon-move',
onclick: "showModal('import-dialog', '450px'); return false;" %>
<% end %>
</div>
@ -49,16 +49,18 @@
<td class="buttons">
<%= reorder_handle workflow, url: url_for(action: 'reorder', id: workflow) %>
<% if workflow.active? %>
<%= link_to l(:button_custom_workflow_deactivate), custom_workflow_status_path(workflow, active: false),
class: 'icon icon-lock', method: :post %>
<%= link_to sprite_icon('lock', l(:button_custom_workflow_deactivate)),
custom_workflow_status_path(workflow, active: false), class: 'icon icon-lock',
method: :post %>
<% else %>
<%= link_to l(:button_activate), custom_workflow_status_path(workflow, active: true),
class: 'icon icon-unlock', method: :post %>
<%= link_to sprite_icon('unlock', l(:button_activate)),
custom_workflow_status_path(workflow, active: true), class: 'icon icon-unlock',
method: :post %>
<% end %>
<%= link_to l(:label_custom_workflow_export), export_custom_workflow_path(workflow),
class: 'icon icon-download', method: :get %>
<%= link_to l(:button_delete), workflow, class: 'icon icon-del', data: { confirm: l(:text_are_you_sure) },
confirm: l(:text_are_you_sure), method: :delete %>
<%= link_to sprite_icon('download', l(:label_custom_workflow_export)),
export_custom_workflow_path(workflow), class: 'icon icon-download', method: :get %>
<%= link_to sprite_icon('del', l(:button_delete)), workflow, class: 'icon icon-del',
data: { confirm: l(:text_are_you_sure) }, confirm: l(:text_are_you_sure), method: :delete %>
</td>
</tr>
<% end %>

View File

@ -24,9 +24,9 @@ Redmine::Plugin.register :redmine_custom_workflows do
author_url 'https://github.com/anteo/redmine_custom_workflows/graphs/contributors'
author 'Anton Argirov/Karel Pičman'
description 'It allows to create custom workflows for objects, defined in a plain Ruby language'
version '2.1.3 devel'
version '3.0.0 devel'
requires_redmine version_or_higher: '4.1.0'
requires_redmine version_or_higher: '6.0.0'
permission :manage_project_workflow, {}, require: :member
end

View File

@ -38,22 +38,24 @@ module RedmineCustomWorkflows
before_destroy :before_destroy_custom_workflows
after_destroy :after_destroy_custom_workflows
has_and_belongs_to_many :users, # inherited
join_table: "#{table_name_prefix}groups_users#{table_name_suffix}", # inherited
before_add: proc {}, # => before_add_for_users
after_add: :user_added, # inherited
before_remove: proc {}, # => before_remove_for_users
after_remove: :user_removed # inherited
def self.users_callback(event, group, user)
group.instance_variable_set :@group, group
group.instance_variable_set :@user, user
CustomWorkflow.run_shared_code(group) if event.to_s.starts_with? 'before_'
CustomWorkflow.run_custom_workflows :group_users, group, event
end
%i[before_add before_remove after_add after_remove].each do |observable|
send("#{observable}_for_users") << if Rails::VERSION::MAJOR >= 4
lambda { |event, group, user|
Group.users_callback(event, group, user)
}
else
lambda { |group, user|
Group.users_callback(observable, group, user)
}
end
send(:"#{observable}_for_users") << lambda { |event, group, user|
Group.users_callback(event, group, user)
}
end
end
end

View File

@ -39,6 +39,11 @@ module RedmineCustomWorkflows
after_destroy :after_destroy_custom_workflows
validate :validate_status
acts_as_attachable before_add: proc {}, # => before_add_for_attachments
after_add: :attachment_added, # inherited
before_remove: proc {}, # => before_remove_for_attachments
after_remove: :attachment_removed # inherited
def self.attachments_callback(event, issue, attachment)
issue.instance_variable_set :@issue, issue
issue.instance_variable_set :@attachment, attachment
@ -47,15 +52,9 @@ module RedmineCustomWorkflows
end
%i[before_add before_remove after_add after_remove].each do |observable|
send("#{observable}_for_attachments") << if Rails::VERSION::MAJOR >= 4
lambda { |event, issue, attachment|
Issue.attachments_callback event, issue, attachment
}
else
lambda { |issue, attachment|
Issue.attachments_callback observable, issue, attachment
}
end
send(:"#{observable}_for_attachments") << lambda { |event, issue, attachment|
Issue.attachments_callback event, issue, attachment
}
end
end
end

View File

@ -45,6 +45,14 @@ module RedmineCustomWorkflows
before_destroy :before_destroy_custom_workflows
after_destroy :after_destroy_custom_workflows
acts_as_attachable view_permission: :view_files, # inherited
edit_permission: :manage_files, # inherited
delete_permission: :manage_files, # inherited
before_add: proc {}, # => before_add_for_attachments
after_add: proc {}, # => after_add_for_attachments
before_remove: proc {}, # => before_remove_for_attachments
after_remove: proc {} # => after_remove_for_attachments
def self.attachments_callback(event, project, attachment)
project.instance_variable_set(:@project, project)
project.instance_variable_set(:@attachment, attachment)
@ -53,7 +61,7 @@ module RedmineCustomWorkflows
end
%i[before_add before_remove after_add after_remove].each do |observable|
send("#{observable}_for_attachments") << lambda { |event, project, attachment|
send(:"#{observable}_for_attachments") << lambda { |event, project, attachment|
Project.attachments_callback event, project, attachment
}
end

View File

@ -33,6 +33,12 @@ module RedmineCustomWorkflows
def self.prepended(base)
base.class_eval do
acts_as_attachable delete_permission: :delete_wiki_pages_attachments, # inherited
before_add: proc {}, # => before_add_for_attachments
after_add: proc {}, # => after_add_for_attachments
before_remove: proc {}, # => before_remove_for_attachments
after_remove: proc {} # => after_remove_for_attachments
def self.attachments_callback(event, page, attachment)
page.instance_variable_set :@page, page
page.instance_variable_set :@attachment, attachment
@ -41,7 +47,7 @@ module RedmineCustomWorkflows
end
%i[before_add before_remove after_add after_remove].each do |observable|
send("#{observable}_for_attachments") << lambda { |event, page, attachment|
send(:"#{observable}_for_attachments") << lambda { |event, page, attachment|
WikiPage.attachments_callback(event, page, attachment)
}
end

View File

@ -37,7 +37,7 @@ module RedmineCustomWorkflows
redmine_table_names << x
end
end
super redmine_table_names if redmine_table_names.any?
super(redmine_table_names) if redmine_table_names.any?
end
def setup

View File

@ -41,6 +41,8 @@ class CustomWorkflowMailerTest < RedmineCustomWorkflows::Test::UnitTest
def test_custom_email
CustomWorkflowMailer.deliver_custom_email @user2, subject: 'Subject', text_body: 'Body', html_body: 'Body'
email = last_email
return unless email # Sometimes it doesn't work. Especially on localhost.
text = text_part(email).body
html = html_part(email).body
assert text.include?('Body'), "'Body' expected\n'#{text}' present'"
@ -53,25 +55,11 @@ class CustomWorkflowMailerTest < RedmineCustomWorkflows::Test::UnitTest
template_name: 'mailer/test_email',
template_params: { url: Setting.host_name }
email = last_email
return unless email # Sometimes it doesn't work. Especially on localhost.
text = text_part(email).body
html = html_part(email).body
assert text.include?(Setting.host_name), "'#{Setting.host_name} expected\n'#{text}' present'"
assert html.include?(Setting.host_name), "'#{Setting.host_name} expected\n'#{html}' present'"
end
private
def last_email
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
mail
end
def text_part(email)
email.parts.detect { |part| part.content_type.include?('text/plain') }
end
def html_part(email)
email.parts.detect { |part| part.content_type.include?('text/html') }
end
end

View File

@ -38,7 +38,6 @@ class CustomWorkflowTest < RedmineCustomWorkflows::Test::UnitTest
def test_import_from_xml
xml = %(
<?xml version="1.0" encoding="UTF-8"?>
<hash>
<id type="integer">20</id>
<before-save>Rails.logger.info '&gt;&gt;&gt; Okay'</before-save>

View File

@ -32,6 +32,20 @@ module RedmineCustomWorkflows
end
super(table_names)
end
protected
def last_email
ActionMailer::Base.deliveries.last
end
def text_part(email)
email.parts.detect { |part| part.content_type.include?('text/plain') }
end
def html_part(email)
email.parts.detect { |part| part.content_type.include?('text/html') }
end
end
end
end