Actualizar plugin Checklists a 3.1.18 light

This commit is contained in:
Manuel Cillero 2020-11-22 21:32:57 +01:00
parent a26f5567af
commit 24560c8598
55 changed files with 992 additions and 307 deletions

View file

@ -1,14 +1,25 @@
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
---
# === Checklist for Issue(1) ===
one:
id: 1
is_done: false
subject: First todo
issue_id: 1
two:
id: 2
is_done: true
subject: Second todo
issue_id: 1
# === Checklist for Issue(2) ===
section_one:
id: 4
is_done: false
subject: New section
is_section: true
issue_id: 2
three:
id: 3
is_done: true

View file

@ -3,7 +3,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine
#
# Copyright (C) 2011-2017 RedmineUP
# Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/
#
# redmine_checklists is free software: you can redistribute it and/or modify
@ -44,8 +44,7 @@ class ChecklistsControllerTest < ActionController::TestCase
:journals,
:journal_details,
:queries
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/',
[:checklists])
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/', [:checklists])
def setup
RedmineChecklists::TestCase.prepare
@ -61,7 +60,7 @@ class ChecklistsControllerTest < ActionController::TestCase
# log_user('admin', 'admin')
@request.session[:user_id] = 1
xhr :put, :done, :is_done => 'true', :id => '1'
compatible_xhr_request :put, :done, :is_done => 'true', :id => '1'
assert_response :success, 'Post done not working'
assert_equal true, Checklist.find(1).is_done, 'Post done not working'
end
@ -70,7 +69,7 @@ class ChecklistsControllerTest < ActionController::TestCase
# log_user('admin', 'admin')
@request.session[:user_id] = 5
xhr :put, :done, :is_done => true, :id => "1"
compatible_xhr_request :put, :done, :is_done => true, :id => "1"
assert_response 403, "Post done accessible for all"
end
@ -78,7 +77,7 @@ class ChecklistsControllerTest < ActionController::TestCase
# log_user('admin', 'admin')
@request.session[:user_id] = 1
@controller = IssuesController.new
get :show, :id => @issue_1.id
compatible_request :get, :show, :id => @issue_1.id
assert_select 'ul#checklist_items li#checklist_item_1', @checklist_1.subject, "Issue won't view for admin"
end
@ -86,7 +85,7 @@ class ChecklistsControllerTest < ActionController::TestCase
# log_user('anonymous', '')
@request.session[:user_id] = 5
@controller = IssuesController.new
get :show, :id => @issue_1.id
compatible_request :get, :show, :id => @issue_1.id
assert_select 'ul#checklist_items', false, "Issue view for anonymous"
end
end

View file

@ -3,7 +3,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine
#
# Copyright (C) 2011-2017 RedmineUP
# Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/
#
# redmine_checklists is free software: you can redistribute it and/or modify
@ -49,71 +49,56 @@ class IssuesControllerTest < ActionController::TestCase
:journal_details,
:queries
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/',
[:checklists])
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/', [:checklists])
def setup
@request.session[:user_id] = 1
RedmineChecklists::TestCase.prepare
end
def test_new_issue_without_project
get :new
compatible_request :get, :new
assert_response :success
end if Redmine::VERSION.to_s > '3.0'
def test_get_show_issue
issue = Issue.find(1)
assert_not_nil issue.checklists.first
get :show, :id => 1
compatible_request(:get, :show, :id => 1)
assert_response :success
assert_select "ul#checklist_items li#checklist_item_1", /First todo/
assert_select "ul#checklist_items li#checklist_item_1 input[checked=?]", "checked", {:count => 0}
assert_select "ul#checklist_items li#checklist_item_1 input[checked=?]", "checked", { :count => 0 }
assert_select "ul#checklist_items li#checklist_item_2 input[checked=?]", "checked"
end
def test_get_edit_issue
get :edit, :id => 1
compatible_request :get, :edit, :id => 1
assert_response :success
end
def test_get_copy_issue
get :new, :project_id => 1, :copy_from => 1
compatible_request :get, :new, :project_id => 1, :copy_from => 1
assert_response :success
assert_select "span#checklist_form_items span.checklist-subject", {:count => 3}
assert_select "span#checklist_form_items span.checklist-subject", { :count => 3 }
assert_select "span#checklist_form_items span.checklist-edit input[value=?]", "First todo"
end
def test_put_update_form
parameters = {:tracker_id => 2,
:checklists_attributes => {
"0" => {"is_done"=>"0", "subject"=>"First"},
"0" => {"is_done"=>"0", "subject"=>"FirstChecklist"},
"1" => {"is_done"=>"0", "subject"=>"Second"}}}
@request.session[:user_id] = 1
issue = Issue.find(1)
if Redmine::VERSION.to_s > '2.3' && Redmine::VERSION.to_s < '3.0'
xhr :put, :update_form,
:issue => parameters,
:project_id => issue.project
compatible_xhr_request :put, :update_form, :issue => parameters, :project_id => issue.project
else
xhr :put, :new,
:issue => parameters,
:project_id => issue.project
compatible_xhr_request :put, :new, :issue => parameters, :project_id => issue.project
end
assert_response :success
assert_equal 'text/javascript', response.content_type
if Redmine::VERSION.to_s < '3.0'
assert_template 'update_form'
else
assert_template 'new'
end
issue = assigns(:issue)
assert_kind_of Issue, issue
assert_match 'First', issue.checklists.map(&:subject).join
assert_match 'FirstChecklist', response.body
end
def test_added_attachment_shows_in_log_once
@ -125,11 +110,10 @@ class IssuesControllerTest < ActionController::TestCase
'1' => { 'is_done' => '0', 'subject' => 'Second' } } }
@request.session[:user_id] = 1
issue = Issue.find(1)
post :update,
:issue => parameters,
:attachments => { '1' => { 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file' } },
:project_id => issue.project,
:id => issue.to_param
compatible_request :post, :update, :issue => parameters,
:attachments => { '1' => { 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file' } },
:project_id => issue.project,
:id => issue.to_param
assert_response :redirect
assert_equal 1, Journal.last.details.where(:property => 'attachment').count
end
@ -144,7 +128,7 @@ class IssuesControllerTest < ActionController::TestCase
:old_value => '[ ] TEST',
:value => '[x] TEST')
post :show, :id => issue.id
compatible_request :post, :show, :id => issue.id
assert_response :success
last_journal = issue.journals.last
assert_equal last_journal.details.size, 1
@ -156,7 +140,7 @@ class IssuesControllerTest < ActionController::TestCase
@request.session[:user_id] = 1
issue = Issue.find(1)
journals_before = issue.journals.count
post :update, :issue => {}, :id => issue.to_param, :project_id => issue.project
compatible_request :post, :update, :issue => {}, :id => issue.to_param, :project_id => issue.project
assert_response :redirect
assert_equal journals_before, issue.reload.journals.count
end
@ -164,11 +148,11 @@ class IssuesControllerTest < ActionController::TestCase
def test_create_issue_without_checklists
@request.session[:user_id] = 1
assert_difference 'Issue.count' do
post :create, :project_id => 1, :issue => { :tracker_id => 3,
:status_id => 2,
:subject => 'NEW issue without checklists',
:description => 'This is the description'
}
compatible_request :post, :create, :project_id => 1, :issue => { :tracker_id => 3,
:status_id => 2,
:subject => 'NEW issue without checklists',
:description => 'This is the description'
}
end
assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
@ -176,18 +160,36 @@ class IssuesControllerTest < ActionController::TestCase
assert_not_nil issue
end
def test_create_issue_with_checklists
@request.session[:user_id] = 1
assert_difference 'Issue.count' do
compatible_request :post, :create, :project_id => 1, :issue => { :tracker_id => 3,
:status_id => 2,
:subject => 'NEW issue with checklists',
:description => 'This is the description',
:checklists_attributes => { '0' => { 'is_done' => '0', 'subject' => 'item 001', 'position' => '1' } }
}
end
assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
issue = Issue.find_by_subject('NEW issue with checklists')
assert_equal 1, issue.checklists.count
assert_equal 'item 001', issue.checklists.last.subject
assert_not_nil issue
end
def test_create_issue_using_json
old_value = Setting.rest_api_enabled
Setting.rest_api_enabled = '1'
@request.session[:user_id] = 1
assert_difference 'Issue.count' do
post :create, :format => :json, :project_id => 1, :issue => { :tracker_id => 3,
:status_id => 2,
:subject => 'NEW JSON issue',
:description => 'This is the description',
:checklists_attributes => [{:is_done => 0, :subject => 'JSON checklist'}]
},
:key => User.find(1).api_key
compatible_request :post, :create, :format => :json, :project_id => 1, :issue => { :tracker_id => 3,
:status_id => 2,
:subject => 'NEW JSON issue',
:description => 'This is the description',
:checklists_attributes => [{ :is_done => 0, :subject => 'JSON checklist' }]
},
:key => User.find(1).api_key
end
assert_response :created
@ -197,4 +199,28 @@ class IssuesControllerTest < ActionController::TestCase
ensure
Setting.rest_api_enabled = old_value
end
def test_history_displaying_for_checklist
@request.session[:user_id] = 1
Setting[:plugin_redmine_checklists] = { save_log: 1, issue_done_ratio: 0 }
issue = Issue.find(1)
journal = issue.journals.create!(user_id: 1)
journal.details.create!(:property => 'attr',
:prop_key => 'checklist',
:old_value => '[ ] TEST',
:value => '[x] TEST')
# With permissions
@request.session[:user_id] = 1
compatible_request :get, :show, id: issue.id
assert_response :success
assert_include 'changed from [ ] TEST to [x] TEST', response.body
# Without permissions
@request.session[:user_id] = 5
compatible_request :get, :show, id: issue.id
assert_response :success
assert_not_include 'changed from [ ] TEST to [x] TEST', response.body
end
end

View file

@ -3,7 +3,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine
#
# Copyright (C) 2011-2017 RedmineUP
# Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/
#
# redmine_checklists is free software: you can redistribute it and/or modify
@ -19,7 +19,7 @@
# You should have received a copy of the GNU General Public License
# along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>.
require File.dirname(__FILE__) + '/../../test_helper'
require File.expand_path('../../../test_helper', __FILE__)
class Redmine::ApiTest::ChecklistsTest < Redmine::ApiTest::Base
fixtures :projects,
@ -46,27 +46,25 @@ class Redmine::ApiTest::ChecklistsTest < Redmine::ApiTest::Base
:journal_details,
:queries
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/',
[:checklists])
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/', [:checklists])
def setup
Setting.rest_api_enabled = '1'
end
def test_get_checklists_xml
get '/issues/1/checklists.xml', {}, credentials('admin')
compatible_api_request :get, '/issues/1/checklists.xml', {}, credentials('admin')
assert_select 'checklists[type=array]' do
assert_select 'checklist' do
assert_select 'id', :text => "1"
assert_select 'subject', :text => "First todo"
assert_select 'id', :text => '1'
assert_select 'subject', :text => 'First todo'
end
end
end
def test_get_checklists_1_xml
get '/checklists/1.xml', {}, credentials('admin')
compatible_api_request :get, '/checklists/1.xml', {}, credentials('admin')
assert_select 'checklist' do
assert_select 'id', :text => '1'
@ -75,11 +73,11 @@ class Redmine::ApiTest::ChecklistsTest < Redmine::ApiTest::Base
end
def test_post_checklists_xml
parameters = {:checklist => {:issue_id => 1,
:subject => 'api_test_001',
:is_done => true}}
parameters = { :checklist => { :issue_id => 1,
:subject => 'api_test_001',
:is_done => true } }
assert_difference('Checklist.count') do
post '/issues/1/checklists.xml', parameters, credentials('admin')
compatible_api_request :post, '/issues/1/checklists.xml', parameters, credentials('admin')
end
checklist = Checklist.order('id DESC').first
@ -91,25 +89,23 @@ class Redmine::ApiTest::ChecklistsTest < Redmine::ApiTest::Base
end
def test_put_checklists_1_xml
parameters = {:checklist => {:subject => 'Item_UPDATED'}}
parameters = { :checklist => { subject: 'Item_UPDATED', is_done: '1' } }
assert_no_difference('Checklist.count') do
put '/checklists/1.xml', parameters, credentials('admin')
compatible_api_request :put, '/checklists/1.xml', parameters, credentials('admin')
end
checklist = Checklist.find(1)
assert_equal parameters[:checklist][:subject], checklist.subject
end
def test_delete_1_xml
assert_difference 'Checklist.count', -1 do
delete '/checklists/1.xml', {}, credentials('admin')
compatible_api_request :delete, '/checklists/1.xml', {}, credentials('admin')
end
assert_response :ok
assert ['200', '204'].include?(response.code)
assert_equal '', @response.body
assert_nil Checklist.find_by_id(1)
end
end

View file

@ -3,7 +3,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine
#
# Copyright (C) 2011-2017 RedmineUP
# Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/
#
# redmine_checklists is free software: you can redistribute it and/or modify
@ -44,23 +44,19 @@ class CommonIssueTest < RedmineChecklists::IntegrationTest
:journals,
:journal_details,
:queries
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/',
[:checklists])
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/', [:checklists])
def setup
RedmineChecklists::TestCase.prepare
Setting.default_language = 'en'
@project_1 = Project.find(1)
@issue_1 = Issue.find(1)
@project_1 = Project.find(1)
@issue_1 = Issue.find(1)
@checklist_1 = Checklist.find(1)
@request = ActionController::TestRequest.new
end
end
test "Global search with checklist" do
# log_user('admin', 'admin')
@request.session[:user_id] = 1
get "/search?q=First"
def test_global_search_with_checklist
log_user('admin', 'admin')
compatible_request :get, '/search?q=First'
assert_response :success
end
end

View file

@ -3,7 +3,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine
#
# Copyright (C) 2011-2017 RedmineUP
# Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/
#
# redmine_checklists is free software: you can redistribute it and/or modify
@ -21,6 +21,39 @@
require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper')
module RedmineChecklists
module TestHelper
def compatible_request(type, action, parameters = {})
return send(type, action, :params => parameters) if Rails.version >= '5.1'
send(type, action, parameters)
end
def compatible_xhr_request(type, action, parameters = {})
return send(type, action, :params => parameters, :xhr => true) if Rails.version >= '5.1'
xhr type, action, parameters
end
def compatible_api_request(type, action, parameters = {}, headers = {})
return send(type, action, :params => parameters, :headers => headers) if Redmine::VERSION.to_s >= '3.4'
send(type, action, parameters, headers)
end
def issues_in_list
ids = css_select('tr.issue td.id a').map { |tag| tag.to_s.gsub(/<.*?>/, '') }.map(&:to_i)
Issue.where(:id => ids).sort_by { |issue| ids.index(issue.id) }
end
def with_checklists_settings(options, &block)
Setting.plugin_redmine_checklists.stubs(:[]).returns(nil)
options.each { |k, v| Setting.plugin_redmine_checklists.stubs(:[]).with(k).returns(v) }
yield
ensure
options.each { |_k, _v| Setting.plugin_redmine_checklists.unstub(:[]) }
end
end
end
include RedmineChecklists::TestHelper
if ActiveRecord::VERSION::MAJOR >= 4
class RedmineChecklists::IntegrationTest < Redmine::IntegrationTest; end
@ -29,7 +62,6 @@ else
end
class RedmineChecklists::TestCase
def self.create_fixtures(fixtures_directory, table_names, class_names = {})
if ActiveRecord::VERSION::MAJOR >= 4
ActiveRecord::FixtureSet.create_fixtures(fixtures_directory, table_names, class_names = {})
@ -39,6 +71,11 @@ class RedmineChecklists::TestCase
end
def self.prepare
Role.find([1,2]).each do |r| # For anonymous
r.permissions << :view_checklists
r.save
end
Role.find(1, 2, 3, 4).each do |r|
r.permissions << :edit_checklists
r.save
@ -53,7 +90,5 @@ class RedmineChecklists::TestCase
r.permissions << :manage_checklist_templates
r.save
end
end
end

View file

@ -3,7 +3,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine
#
# Copyright (C) 2011-2017 RedmineUP
# Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/
#
# redmine_checklists is free software: you can redistribute it and/or modify
@ -46,8 +46,7 @@ class ChecklistTest < ActiveSupport::TestCase
:journal_details,
:queries
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/',
[:checklists])
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/', [:checklists])
def setup
RedmineChecklists::TestCase.prepare
Setting.default_language = 'en'
@ -56,11 +55,8 @@ class ChecklistTest < ActiveSupport::TestCase
:status_id => 1, :priority => IssuePriority.first,
:subject => 'Invoice Issue 1')
@checklist_1 = Checklist.create(:subject => 'TEST1', :position => 1, :issue => @issue_1)
end
test "should save checklist" do
assert @checklist_1.save, "Checklist save error"
end
@ -90,4 +86,53 @@ class ChecklistTest < ActiveSupport::TestCase
assert_equal "[x] #{@checklist_1.subject}", @checklist_1.info, "Helper info broken"
end
def test_should_correct_recalculate_rate
issues = [
[Issue.create(project_id: 1, tracker_id: 1, author_id: 1, status_id: 1, priority: IssuePriority.first, subject: "TI #1", done_ratio: 0,
checklists_attributes: {
'0' => { subject: 'item 1', is_done: false },
'1' => { subject: 'item 2', is_done: false },
'2' => { subject: 'item 3', is_done: true },
}),
30],
[Issue.create(project_id: 1, tracker_id: 1, author_id: 1, status_id: 1, priority: IssuePriority.first, subject: "TI #2", done_ratio: 0,
checklists_attributes: {
'0' => { subject: 'item 1', is_done: false },
'1' => { subject: 'item 2', is_done: true },
'2' => { subject: 'item 3', is_done: true },
}),
60],
[Issue.create(project_id: 1, tracker_id: 1, author_id: 1, status_id: 1, priority: IssuePriority.first, subject: "TI #3", done_ratio: 0,
checklists_attributes: {
'0' => { subject: 'item 1', is_done: true },
'1' => { subject: 'item 2', is_done: true },
'2' => { subject: 'item 3', is_done: true },
}),
100],
[Issue.create(project_id: 1, tracker_id: 1, author_id: 1, status_id: 1, priority: IssuePriority.first, subject: "TI #4", done_ratio: 0,
checklists_attributes: {
'0' => { subject: 'item 1', is_done: false },
'1' => { subject: 'item 2', is_done: false },
'2' => { subject: 'section 1', is_done: true, is_section: true },
'3' => { subject: 'item 3', is_done: true },
}),
30],
[Issue.create(project_id: 1, tracker_id: 1, author_id: 1, status_id: 1, priority: IssuePriority.first, subject: "TI #5", done_ratio: 0,
checklists_attributes: {
'0' => { subject: 'section 1', is_done: true, is_section: true }
}),
0]
]
with_checklists_settings('issue_done_ratio' => '1') do
issues.each do |issue, after_ratio|
assert_equal 0, issue.done_ratio
Checklist.recalc_issue_done_ratio(issue.id)
issue.reload
assert_equal after_ratio, issue.done_ratio
end
end
ensure
issues.each { |issue, ratio| issue.destroy }
end
end

View file

@ -0,0 +1,85 @@
# encoding: utf-8
#
# This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine
#
# Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/
#
# redmine_checklists 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 3 of the License, or
# (at your option) any later version.
#
# redmine_checklists 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 redmine_checklists. If not, see <http://www.gnu.org/licenses/>.
require File.expand_path('../../test_helper', __FILE__)
include RedmineChecklists::TestHelper
class IssueTest < ActiveSupport::TestCase
fixtures :projects,
:users,
:roles,
:members,
:member_roles,
:issues,
:issue_statuses,
:versions,
:trackers,
:projects_trackers,
:issue_categories,
:enabled_modules,
:enumerations,
:attachments,
:workflows,
:custom_fields,
:custom_values,
:custom_fields_projects,
:custom_fields_trackers,
:time_entries,
:journals,
:journal_details,
:queries
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/', [:checklists])
def setup
RedmineChecklists::TestCase.prepare
Setting.default_language = 'en'
@project = Project.find(1)
@issue = Issue.create(:project => @project, :tracker_id => 1, :author_id => 1,
:status_id => 1, :priority => IssuePriority.first,
:subject => 'TestIssue')
@checklist_1 = Checklist.create(:subject => 'TEST1', :position => 1, :issue => @issue)
@checklist_2 = Checklist.create(:subject => 'TEST2', :position => 2, :issue => @issue, :is_done => true)
@issue.reload
end
def test_issue_shouldnt_close_when_it_has_unfinished_checklists
with_checklists_settings('block_issue_closing' => '1') do
@issue.status_id = 5
assert !@issue.valid?
end
end
def test_validation_should_be_ignored_if_setting_disabled
with_checklists_settings('block_issue_closing' => '0') do
@issue.status_id = 5
assert @issue.valid?
end
end
def test_issue_should_close_when_all_checklists_finished
with_checklists_settings('block_issue_closing' => '1') do
@checklist_1.update_attributes(:is_done => true)
assert @issue.valid?
end
ensure
@checklist_1.update_attributes(:is_done => false)
end
end

View file

@ -3,7 +3,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine
#
# Copyright (C) 2011-2017 RedmineUP
# Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/
#
# redmine_checklists is free software: you can redistribute it and/or modify