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

@ -0,0 +1 @@
gem 'redmine_crm'

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -20,9 +20,9 @@
class ChecklistsController < ApplicationController class ChecklistsController < ApplicationController
unloadable unloadable
before_filter :find_checklist_item, :except => [:index, :create] before_action :find_checklist_item, :except => [:index, :create]
before_filter :find_issue_by_id, :only => [:index, :create] before_action :find_issue_by_id, :only => [:index, :create]
before_filter :authorize, :except => [:done] before_action :authorize, :except => [:done]
helper :issues helper :issues
accept_api_auth :index, :update, :destroy, :create, :show accept_api_auth :index, :update, :destroy, :create, :show
@ -48,11 +48,13 @@ class ChecklistsController < ApplicationController
end end
def create def create
@checklist_item = Checklist.new(params[:checklist]) @checklist_item = Checklist.new
@checklist_item.safe_attributes = params[:checklist]
@checklist_item.issue = @issue @checklist_item.issue = @issue
respond_to do |format| respond_to do |format|
format.api { format.api {
if @checklist_item.save if @checklist_item.save
recalculate_issue_ratio(@checklist_item)
render :action => 'show', :status => :created, :location => checklist_url(@checklist_item) render :action => 'show', :status => :created, :location => checklist_url(@checklist_item)
else else
render_validation_errors(@checklist_item) render_validation_errors(@checklist_item)
@ -62,9 +64,11 @@ class ChecklistsController < ApplicationController
end end
def update def update
@checklist_item.safe_attributes = params[:checklist]
respond_to do |format| respond_to do |format|
format.api { format.api {
if @checklist_item.update_attributes(params[:checklist]) if with_issue_journal { @checklist_item.save }
recalculate_issue_ratio(@checklist_item)
render_api_ok render_api_ok
else else
render_validation_errors(@checklist_item) render_validation_errors(@checklist_item)
@ -75,12 +79,12 @@ class ChecklistsController < ApplicationController
def done def done
(render_403; return false) unless User.current.allowed_to?(:done_checklists, @checklist_item.issue.project) (render_403; return false) unless User.current.allowed_to?(:done_checklists, @checklist_item.issue.project)
@checklist_item.is_done = params[:is_done] == 'true'
if @checklist_item.save with_issue_journal do
if (Setting.issue_done_ratio == "issue_field") && RedmineChecklists.settings["issue_done_ratio"].to_i > 0 @checklist_item.is_done = params[:is_done] == 'true'
Checklist.recalc_issue_done_ratio(@checklist_item.issue.id) if @checklist_item.save
@checklist_item.issue.reload recalculate_issue_ratio(@checklist_item)
true
end end
end end
respond_to do |format| respond_to do |format|
@ -104,4 +108,15 @@ class ChecklistsController < ApplicationController
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
end end
def with_issue_journal(&block)
return unless yield
end
def recalculate_issue_ratio(checklist_item)
if (Setting.issue_done_ratio == 'issue_field') && RedmineChecklists.issue_done_ratio?
Checklist.recalc_issue_done_ratio(checklist_item.issue.id)
checklist_item.issue.reload
end
end
end end

View file

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

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -22,10 +22,9 @@ class Checklist < ActiveRecord::Base
include Redmine::SafeAttributes include Redmine::SafeAttributes
belongs_to :issue belongs_to :issue
belongs_to :author, :class_name => "User", :foreign_key => "author_id" belongs_to :author, :class_name => "User", :foreign_key => "author_id"
has_one :comment, :as => :commented, :dependent => :delete
if ActiveRecord::VERSION::MAJOR >= 4 attr_protected :id if ActiveRecord::VERSION::MAJOR <= 4
attr_protected :id
end
acts_as_event :datetime => :created_at, acts_as_event :datetime => :created_at,
:url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue_id}}, :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue_id}},
:type => 'issue issue-closed', :type => 'issue issue-closed',
@ -51,17 +50,17 @@ class Checklist < ActiveRecord::Base
:order_column => "#{table_name}.id" :order_column => "#{table_name}.id"
end end
acts_as_list rcrm_acts_as_list
validates_presence_of :subject validates_presence_of :subject
validates_length_of :subject, :maximum => 512 validates_length_of :subject, maximum: 512
validates_presence_of :position validates_presence_of :position
validates_numericality_of :position validates_numericality_of :position
def self.recalc_issue_done_ratio(issue_id) def self.recalc_issue_done_ratio(issue_id)
issue = Issue.find(issue_id) issue = Issue.find(issue_id)
return false if (Setting.issue_done_ratio != "issue_field") || RedmineChecklists.settings["issue_done_ratio"].to_i < 1 || issue.checklists.empty? return false if (Setting.issue_done_ratio != 'issue_field') || !RedmineChecklists.issue_done_ratio? || issue.checklists.reject(&:is_section).empty?
done_checklist = issue.checklists.map{|c| c.is_done ? 1 : 0} done_checklist = issue.checklists.reject(&:is_section).map { |c| c.is_done ? 1 : 0 }
done_ratio = (done_checklist.count(1) * 10) / done_checklist.count * 10 done_ratio = (done_checklist.count(1) * 10) / done_checklist.count * 10
issue.update_attribute(:done_ratio, done_ratio) issue.update_attribute(:done_ratio, done_ratio)
end end
@ -71,7 +70,7 @@ class Checklist < ActiveRecord::Base
(detail.value.is_a?(String) && detail.value.match(/^\[[ |x]\] .+$/).present?) (detail.value.is_a?(String) && detail.value.match(/^\[[ |x]\] .+$/).present?)
end end
safe_attributes 'subject', 'position', 'issue_id', 'is_done' safe_attributes 'subject', 'position', 'issue_id', 'is_done', 'is_section'
def editable_by?(usr = User.current) def editable_by?(usr = User.current)
usr && (usr.allowed_to?(:edit_checklists, project) || (author == usr && usr.allowed_to?(:edit_own_checklists, project))) usr && (usr.allowed_to?(:edit_checklists, project) || (author == usr && usr.allowed_to?(:edit_own_checklists, project)))

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -19,27 +19,24 @@
class JournalChecklistHistory class JournalChecklistHistory
def self.can_fixup?(journal_details) def self.can_fixup?(journal_details)
unless journal_details.journal return false if journal_details.journal.nil?
return false
end
issue = journal_details.journal.journalized issue = journal_details.journal.journalized
unless issue.is_a?(Issue) return false unless issue.is_a?(Issue)
return false
end
prev_journal_scope = issue.journals.order('id DESC') prev_journal_scope = issue.journals.order('id DESC')
prev_journal_scope = prev_journal_scope.where('id <> ?', journal_details.journal_id) if journal_details.journal_id prev_journal_scope = prev_journal_scope.where('id <> ?', journal_details.journal_id) if journal_details.journal_id
prev_journal = prev_journal_scope.first prev_journal = prev_journal_scope.first
unless prev_journal return false unless prev_journal
return false
end
return false if prev_journal.user_id != journal_details.journal.user_id
return false if Time.zone.now > prev_journal.created_on + 1.minute return false if Time.zone.now > prev_journal.created_on + 1.minute
prev_journal.details.all?{ |x| x.prop_key == 'checklist'} && prev_journal.details.all? { |x| x.prop_key == 'checklist' } &&
journal_details.journal.details.all?{ |x| x.prop_key == 'checklist'} && journal_details.journal.details.all? { |x| x.prop_key == 'checklist' } &&
journal_details.journal.notes.blank? && journal_details.journal.notes.blank? &&
prev_journal.notes.blank? && prev_journal.notes.blank? &&
prev_journal.details.select{ |x| x.prop_key == 'checklist' }.size == 1 prev_journal.details.select { |x| x.prop_key == 'checklist' }.size == 1
end end
def self.fixup(journal_details) def self.fixup(journal_details)

View file

@ -1,8 +1,11 @@
<li id="checklist_item_<%= checklist_item.id %>" <%= "class=is-done-checklist-item" if checklist_item.is_done %> > <li id="checklist_item_<%= checklist_item.id %>" class="<%= 'is-done-checklist-item' if checklist_item.is_done %> <%= 'checklist-section' if checklist_item.is_section %>">
<%= check_box_tag 'checklist_item', "", checklist_item.is_done, <% unless checklist_item.is_section %>
:disabled => !User.current.allowed_to?(:done_checklists, checklist_item.issue.project) && !User.current.allowed_to?(:edit_checklists, checklist_item.issue.project), <%= check_box_tag 'checklist_item', '', checklist_item.is_done,
:data_url => url_for( {:controller => "checklists", :action => "done", :id => checklist_item.id} ), :class => 'checklist-checkbox' disabled: !User.current.allowed_to?(:done_checklists, checklist_item.issue.project) && !User.current.allowed_to?(:edit_checklists, checklist_item.issue.project),
%> data_url: url_for({ controller: 'checklists', action: 'done', id: checklist_item.id }),
class: 'checklist-checkbox',
id: "checklist-checkbox-#{checklist_item.id}"
%>
<% end %>
<%= textilizable(checklist_item, :subject).gsub(/<\/?(p|h\d+|li|ul)>/, '').strip.html_safe %> <%= textilizable(checklist_item, :subject).gsub(/<\/?(p|h\d+|li|ul)>/, '').strip.html_safe %>
</li> </li>

View file

@ -2,3 +2,16 @@ $("#checklist_item_<%= @checklist_item.id %>").toggleClass('is-done-checklist-it
$('#checklist_form .checklist-item#<%= @checklist_item.id %> input[type=checkbox]').trigger('click'); $('#checklist_form .checklist-item#<%= @checklist_item.id %> input[type=checkbox]').trigger('click');
$('.issue .attributes table.progress').parent().html('<%= j(progress_bar(@checklist_item.issue.done_ratio, :width => '80px', :legend => "#{@checklist_item.issue.done_ratio}%")) %>'); $('.issue .attributes table.progress').parent().html('<%= j(progress_bar(@checklist_item.issue.done_ratio, :width => '80px', :legend => "#{@checklist_item.issue.done_ratio}%")) %>');
$('#issue_done_ratio').val('<%= @checklist_item.issue.done_ratio %>'); $('#issue_done_ratio').val('<%= @checklist_item.issue.done_ratio %>');
var checkedCheckboxes = $('.checklist-checkbox:checkbox:checked');
if(localStorage.getItem("hide_closed_checklists") === '0' && checkedCheckboxes.length > 0){
$("#checklist_item_<%= @checklist_item.id %>").fadeOut(1000).hide(15);
$('#switch_link').text('<%= l("label_checklist_show_closed") %>' + '(' + checkedCheckboxes.length + ')');
}
if(checkedCheckboxes.length < 1 && localStorage.getItem("hide_closed_checklists") === '1'){
$('#switch_link').hide();
}
if(checkedCheckboxes.length > 0){
$('#switch_link').show();
}

View file

@ -1,7 +1,9 @@
<% if !@issue.blank? && @issue.checklists.any? && User.current.allowed_to?(:view_checklists, @project) %> <% if !@issue.blank? && @issue.checklists.any? && User.current.allowed_to?(:view_checklists, @project) %>
<hr /> <hr />
<div id="checklist"> <div id="checklist">
<div class="contextual">
<%= link_to l("label_checklist_hide_closed"), '#', id: 'switch_link' %>
</div>
<p><strong><%=l(:label_checklist_plural)%></strong></p> <p><strong><%=l(:label_checklist_plural)%></strong></p>
<ul id="checklist_items"> <ul id="checklist_items">
@ -11,6 +13,7 @@
<% end %> <% end %>
</ul> </ul>
</div> </div>
<%= javascript_tag do %>
new Redmine.ChecklistToggle('<%= l("label_checklist_show_closed") %>', '<%= l("label_checklist_hide_closed") %>');
<% end %>
<% end %> <% end %>

View file

@ -1,21 +1,26 @@
<span class="checklist-item <%= new_or_show(f) %>" id = "<%=f.object.id%>"> <span class="checklist-item <%= new_or_show(f) %> <%= 'checklist-section' if f.object.is_section %>" id="<%= f.object.id %>">
<span class = "checklist-show-only checklist-checkbox"><%= f.check_box :is_done %></span> <% unless f.object.is_section %>
<span class = "checklist-show checklist-subject <%= done_css(f) %>"> <span class="checklist-show-only checklist-checkbox"><%= f.check_box :is_done %></span>
<%= f.object.subject %> <% end %>
<span class="checklist-show checklist-subject <%= done_css(f) %>">
<%= textilizable(f.object, :subject).gsub(/<\/?(p|h\d+|li|ul)>/, '').strip.html_safe %>
</span> </span>
<span class = "checklist-edit checklist-new checklist-edit-box">
<%= text_field_tag nil, f.object.subject, :class => 'edit-box'%> <span class="checklist-edit checklist-new checklist-edit-box">
<%= f.hidden_field :subject, :class => 'checklist-subject-hidden' %> <%= text_field_tag nil, f.object.subject, class: 'edit-box' %>
<%= f.hidden_field :subject, class: 'checklist-subject-hidden' %>
</span> </span>
<span class= "checklist-edit-only checklist-edit-save-button"><%= submit_tag l(:button_save), :type => "button", :class => "item item-save small"%> </span>
<span class= "checklist-edit-only checklist-edit-reset-button"><% concat l(:button_cancel) <span class="checklist-edit-only checklist-edit-save-button"><%= submit_tag l(:button_save), type: 'button', class: 'item item-save small' %> </span>
%> </span> <span class="checklist-edit-only checklist-edit-reset-button"><% concat l(:button_cancel) %> </span>
<span class = "checklist-show-only checklist-remove"><%= link_to_remove_checklist_fields "", f, <span class="checklist-show-only checklist-remove"><%= link_to_remove_checklist_fields "", f, class: 'icon icon-del' %></span>
:class => "icon icon-del" %></span>
<%= f.hidden_field :position, :class => 'checklist-item-position' %> <%= f.hidden_field :position, class: 'checklist-item-position' %>
<%= f.hidden_field :id, :class => 'checklist-item-id' %> <%= f.hidden_field :is_section, class: 'checklist-item-is_section' %>
<span class = "icon icon-add checklist-new-only save-new-by-button"></span> <%= f.hidden_field :id, class: 'checklist-item-id' %>
<span class="icon icon-add checklist-new-only save-new-by-button"></span>
<br> <br>
</span> </span>

View file

@ -5,3 +5,9 @@
<%= check_box_tag 'settings[issue_done_ratio]', 1, @settings["issue_done_ratio"].to_i > 0 %> <%= check_box_tag 'settings[issue_done_ratio]', 1, @settings["issue_done_ratio"].to_i > 0 %>
</p> </p>
<% end %> <% end %>
<p>
<label for="settings_block_issue_closing"><%= l(:label_checklist_block_issue_closing) %></label>
<%= hidden_field_tag 'settings[block_issue_closing]', 0, :id => nil %>
<%= check_box_tag 'settings[block_issue_closing]', 1, @settings["block_issue_closing"].to_i > 0 %>
</p>

View file

@ -110,15 +110,11 @@ Redmine.Checklist = $.klass({
event.returnValue = false event.returnValue = false
}, },
addChecklistFields: function(templateDiv) { addChecklistFields: function() {
var new_id = new Date().getTime(); var new_id = new Date().getTime();
var regexp = new RegExp("new_checklist", "g"); var regexp = new RegExp("new_checklist", "g");
if (templateDiv) { appended = $(this.content.replace(regexp, new_id)).appendTo(this.root);
appended = $(this.content.replace(regexp, new_id)).insertBefore(templateDiv) appended.find('.edit-box').focus();
} else {
appended = $(this.content.replace(regexp, new_id)).appendTo(this.root)
}
appended.find('.edit-box').focus()
}, },
findSpan: function(event) { findSpan: function(event) {
@ -129,13 +125,16 @@ Redmine.Checklist = $.klass({
return elem.prevAll('span.checklist-item.new') return elem.prevAll('span.checklist-item.new')
}, },
transformItem: function(event, elem, valueToSet) { transformItem: function(event, elem, valueToSet, isSection) {
var checklistItem; var checklistItem;
if (event) { if (event) {
checklistItem = this.findSpan(event) checklistItem = this.findSpan(event)
} else { } else if (elem) {
checklistItem = this.findSpanBefore(elem) checklistItem = this.findSpanBefore(elem)
} else {
checklistItem = this.root.find('span.checklist-item.new')
} }
var val; var val;
if (valueToSet) { if (valueToSet) {
val = valueToSet val = valueToSet
@ -143,11 +142,17 @@ Redmine.Checklist = $.klass({
} else { } else {
val = checklistItem.find('input.edit-box').val() val = checklistItem.find('input.edit-box').val()
} }
checklistItem.find('.checklist-subject').text(val) checklistItem.find('.checklist-subject').text(val)
checklistItem.find('.checklist-subject-hidden').val(val) checklistItem.find('.checklist-subject-hidden').val(val)
checklistItem.removeClass('edit') checklistItem.removeClass('edit')
checklistItem.removeClass('new') checklistItem.removeClass('new')
checklistItem.addClass('show') checklistItem.addClass('show')
if (isSection) {
checklistItem.addClass('checklist-section');
checklistItem.children('.checklist-item-is_section').val(true);
}
}, },
resetItem: function(item) { resetItem: function(item) {
@ -157,12 +162,9 @@ Redmine.Checklist = $.klass({
}, },
addChecklistItem: function(event) { addChecklistItem: function(event) {
this.preventEvent(event) this.preventEvent(event);
this.transformItem(event) this.transformItem(event);
if ($('.template-wrapper').length) this.addChecklistFields();
this.addChecklistFields($('.template-wrapper'))
else
this.addChecklistFields()
}, },
canSave: function(span) { canSave: function(span) {
@ -193,6 +195,57 @@ Redmine.Checklist = $.klass({
}, this)) }, this))
}, },
onClickAddChecklistItemMenuButton: function() {
$('#checklist-menu .add-checklist-item').on('click', $.proxy(function(event) {
this.preventEvent(event);
var span = $('#checklist_form_items > span.checklist-item.new');
if (this.canSave(span)) {
this.transformItem();
this.addChecklistFields();
this.$plusButtonMenu.hide();
}
}, this))
},
onClickNewSectionMenuButton: function() {
$('#checklist-menu .add-checklist-section').on('click', $.proxy(function(event) {
this.preventEvent(event);
var span = $('#checklist_form_items > span.checklist-item.new');
if (this.canSave(span)) {
this.transformItem(null, null, null, true);
this.addChecklistFields();
this.$plusButtonMenu.hide();
}
}, this))
},
onMouseEnterLeavePlusButton: function() {
var hideMenuTimer;
var $menu = this.$plusButtonMenu;
this.root.on('mouseenter', '.save-new-by-button', function() {
var $plusButton = $(this);
var position = $plusButton.position();
$menu.css('left', (position.left + 'px'));
$menu.css('top', (position.top + $plusButton.height() + 'px'));
$menu.show();
});
this.root.on('mouseleave', '.save-new-by-button', function() {
hideMenuTimer = setTimeout(function() {
$menu.hide();
}, 500);
});
$('#checklist-menu').on('mouseenter', function() {
clearTimeout(hideMenuTimer);
});
$('#checklist-menu').on('mouseleave', function() {
$menu.hide();
});
},
onIssueFormSubmitRemoveEmptyChecklistItems: function() { onIssueFormSubmitRemoveEmptyChecklistItems: function() {
$('body').on('submit', '#issue-form', function(){ $('body').on('submit', '#issue-form', function(){
$('.checklist-subject-hidden').each(function(i, elem) { $('.checklist-subject-hidden').each(function(i, elem) {
@ -206,16 +259,19 @@ Redmine.Checklist = $.klass({
onChecklistRemove: function() { onChecklistRemove: function() {
this.root.on('click', '.checklist-remove a', $.proxy(function(event){ this.root.on('click', '.checklist-remove a', $.proxy(function(event){
this.preventEvent(event) this.preventEvent(event);
removed = this.findSpan(event) var itemToRemove = this.findSpan(event);
removed.find('.checklist-remove input[type=hidden]').val('1') var checkbox = itemToRemove.find(".checklist-remove input[type=hidden]");
removed.fadeOut(200)
}, this)) if (checkbox.val() === "false") {
checkbox.val("1");
itemToRemove.fadeOut(200);
}
}, this));
}, },
makeChecklistsSortable: function() { makeChecklistsSortable: function() {
$('#checklist_form_items').sortable({ $('#checklist_form_items').sortable({
revert: true,
items: '.checklist-item.show', items: '.checklist-item.show',
helper: "clone", helper: "clone",
stop: function (event, ui) { stop: function (event, ui) {
@ -265,13 +321,33 @@ Redmine.Checklist = $.klass({
}, },
onChangeCheckbox: function(){ onChangeCheckbox: function(){
this.root.on('change', 'input.checklist-checkbox', $.proxy(function(event){ this.root.on('change', 'input.checklist-checkbox', $.proxy(function(event) {
this.darkenCompletedSections();
checkbox = $(event.target) checkbox = $(event.target)
url = checkbox.attr('data_url') url = checkbox.attr('data_url')
$.ajax({type: "PUT", url: url, data: { is_done: checkbox.prop('checked') }, dataType: 'script'}) $.ajax({type: "PUT", url: url, data: { is_done: checkbox.prop('checked') }, dataType: 'script'})
}, this)) }, this))
}, },
darkenCompletedSections: function() {
var isCompletedSection = true;
var reversedChecklistItems = $('#checklist_items li').get().reverse();
$(reversedChecklistItems).each(function(index, element) {
var $element = $(element);
if ($element.hasClass('checklist-section')) {
if (isCompletedSection) {
$element.addClass('completed-section')
} else {
$element.removeClass('completed-section')
}
isCompletedSection = true;
} else {
isCompletedSection = isCompletedSection && $element.children('.checklist-checkbox').is(':checked')
}
})
},
enableUniquenessValidation: function() { enableUniquenessValidation: function() {
this.root.on('keyup', 'input.edit-box', $.proxy(function(event) { this.root.on('keyup', 'input.edit-box', $.proxy(function(event) {
value = $(event.target).val() value = $(event.target).val()
@ -303,39 +379,39 @@ Redmine.Checklist = $.klass({
}, },
assignTemplateSelectedEvent: function() { assignTemplateSelectedEvent: function() {
var item; this.$plusButtonMenu.on('click', 'li a.checklist-template', $.proxy(function(event) {
this.root.on('change', '#checklist_template', $.proxy(function(){ this.preventEvent(event);
value = $('#checklist_template').val() items = $(event.target).data('template-items').split(/\n/);
selected = $('#checklist_template option[value='+value+']').data('template-items') for(var i = 0; i < items.length; i++) {
items = selected.split(/\n/) var item = items[i];
for(i = 0; i<items.length; i++) var isSection = item.slice(0, 2) === '--';
{ if (isSection) { item = item.slice(2) }
item = items[i] if (!this.hasAlreadyChecklistWithName(item)) {
if (!this.hasAlreadyChecklistWithName(item)) this.transformItem(null, null, item, isSection);
{ this.addChecklistFields();
this.transformItem(null, $('#checklist_template'), item)
this.addChecklistFields($('#template-link').closest('span'))
} }
} }
$('#checklist_template').val('')
$('#template-link').show()
$('#checklist_template').hide()
}, this)) }, this))
}, },
clickSelectTemplateLink: function() {
this.root.on('click', '#template-link', function(){
$('#template-link').hide()
$('#checklist_template').show()
})
},
init: function(element) { init: function(element) {
this.root = element this.root = element
this.content = element.data('checklist-fields') this.content = element.data('checklist-fields')
this.onEnterInNewChecklistItemForm() this.onEnterInNewChecklistItemForm()
this.onClickPlusInNewChecklistItem() this.onClickPlusInNewChecklistItem()
if (this.content) {
this.$plusButtonMenu = $('#checklist-menu').menu();
if (this.$plusButtonMenu.length > 0) {
this.onMouseEnterLeavePlusButton();
this.onClickAddChecklistItemMenuButton();
this.assignTemplateSelectedEvent();
this.onClickNewSectionMenuButton();
}
} else {
this.darkenCompletedSections()
}
this.onIssueFormSubmitRemoveEmptyChecklistItems() this.onIssueFormSubmitRemoveEmptyChecklistItems()
this.onChecklistRemove() this.onChecklistRemove()
this.makeChecklistsSortable() this.makeChecklistsSortable()
@ -343,12 +419,59 @@ Redmine.Checklist = $.klass({
this.onCheckboxChanged() this.onCheckboxChanged()
this.onChangeCheckbox() this.onChangeCheckbox()
this.enableUniquenessValidation() this.enableUniquenessValidation()
this.assignTemplateSelectedEvent()
this.clickSelectTemplateLink()
} }
}) })
$.fn.checklist = function(element){ $.fn.checklist = function(element){
new Redmine.Checklist(this); new Redmine.Checklist(this);
} };
Redmine.ChecklistToggle = $.klass({
manageToggling: function (t_val) {
var checkedCheckboxes = $('.checklist-checkbox:checkbox:checked');
if(localStorage.getItem("hide_closed_checklists") === t_val){
$($(checkedCheckboxes).closest('li')).hide();
$(this.switch_link).text(this.show_text + '(' + checkedCheckboxes.length + ')');
} else {
$($(checkedCheckboxes).closest('li')).show();
$(this.switch_link).text(this.hide_text);
}
},
switch_link_click: function(){
var th = $(this)[0];
this.switch_link.click(function (e) {
e.preventDefault();
th.manageToggling("1");
var setVal = (localStorage.getItem("hide_closed_checklists") === "1") ? "0" : "1";
localStorage.setItem("hide_closed_checklists", setVal);
});
},
hide_switch_link: function(){
if($('.checklist-checkbox:checkbox:checked').length < 1){
this.switch_link.hide();
}
},
init: function(show_text, hide_text) {
this.show_text = show_text;
this.hide_text = hide_text;
this.switch_link = $('#switch_link');
this.manageToggling("0");
this.switch_link_click();
this.hide_switch_link();
}
});
$(document).ready(function () {
if (typeof(contextMenuCheckSelectionBox) === 'function') {
var originContextMenuCheckSelectionBox = contextMenuCheckSelectionBox;
contextMenuCheckSelectionBox = function (tr, checked) {
var $td = tr.find('td.checklist_relations');
var $checklist = $td.find('.checklist').detach();
originContextMenuCheckSelectionBox(tr, checked);
$checklist.appendTo($td);
};
}
});

View file

@ -1,3 +1,7 @@
#checklist_form_items input[type="checkbox"],
#checklist_items input[type="checkbox"] {
height: initial;
}
div#checklist ul { div#checklist ul {
list-style: none; list-style: none;
@ -10,6 +14,8 @@ div#checklist li {
margin-left: 10px; margin-left: 10px;
} }
.checklist-checkbox {height: inherit}
#checklist li:hover a.delete {opacity: 1;} #checklist li:hover a.delete {opacity: 1;}
#checklist a.delete {opacity: 0.4;} #checklist a.delete {opacity: 0.4;}
@ -74,4 +80,65 @@ span.checklist-item.edit .checklist-show-only {
div#checklist ol { div#checklist ol {
display: inline-block; display: inline-block;
padding-left: 0; padding-left: 0;
} }
.checklist-section {
padding-top: 10px;
font-weight: bold;
border-bottom-width: 1px;
border-bottom-style: solid;
border-bottom-color: #eee;
}
.checklist-item.checklist-section > .checklist-checkbox { display: none; }
#checklist_items li.checklist-section {
padding-bottom: 5px;
margin-bottom: 5px;
}
.completed-section { color: #999; }
.save-new-by-button { cursor: pointer; }
table.list td.checklist_relations { text-align: left }
/* ========================================================================= */
/* Checklist context menu */
/* ========================================================================= */
#checklist-menu ul, #checklist-menu li, #checklist-menu a {
display:block;
margin:0;
padding:0;
border:0;
}
#checklist-menu {
display: none;
position: absolute;
font-size: 0.9em;
}
#checklist-menu, #checklist-menu ul {
width: 150px;
border: 1px solid #ccc;
background: white;
list-style: none;
padding: 2px;
border-radius: 2px;
}
#checklist-menu li {
position: relative;
padding: 1px;
border: 1px solid white;
}
#checklist-menu a {
text-decoration: none !important;
padding: 2px 0px 2px 20px;
}
#checklist-menu a:hover { color:#2A5685; }
#checklist-menu li:hover { border:1px solid #628db6; background-color:#eef5fd; border-radius:3px; }

View file

@ -25,5 +25,12 @@ de:
label_checklist_changed_to: zu label_checklist_changed_to: zu
label_checklist_added: hinzugefügt label_checklist_added: hinzugefügt
label_checklist_done: als Erledigt markiert label_checklist_done: als Erledigt markiert
label_checklist_undone: als Nicht Erledigt markiert label_checklist_undone: als Nicht erledigt markiert
label_checklist_updated: Checklisten-Eintrag editiert label_checklist_updated: Checklisten-Eintrag editiert
label_checklist_status: Checklisten-Status
label_checklist_status_done: Erledigt
label_checklist_status_undone: Nicht erledigt
label_checklist_is_default: Standard
field_is_for_tracker: Tracker
label_checklists_must_be_completed: "Alle Checklisten-Einträge eines Tickets müssen vor dem Schließen erledigt werden."
label_checklist_block_issue_closing: "Schließen des Tickets blockieren"

View file

@ -1,5 +1,9 @@
# English strings go here for Rails i18n # English strings go here for Rails i18n
en: en:
activerecord:
attributes:
checklists:
subject: Checklist subject
label_checklist_plural: Checklist label_checklist_plural: Checklist
field_checklist: Checklist field_checklist: Checklist
label_checklist_save_log: Save changes to issue log label_checklist_save_log: Save changes to issue log
@ -15,10 +19,12 @@ en:
field_template_items: Template items field_template_items: Template items
label_checklist_template: Checklist template label_checklist_template: Checklist template
label_add_checklists_from_template: Add from template label_add_checklists_from_template: Add from template
label_checklists_from_template: From template
label_select_template: "-- Select template --" label_select_template: "-- Select template --"
label_checklist_category_not_specified: "-- Not specified --" label_checklist_category_not_specified: "-- Not specified --"
label_checklists_description: 'Multiple values allowed (one line for each value)' label_checklists_description: 'Multiple values allowed (one line for each value)'
label_checklist_item: Checklist item label_checklist_item: Checklist item
label_checklist_section: Checklist section
label_checklist_deleted: deleted label_checklist_deleted: deleted
label_checklist_changed_from: changed from label_checklist_changed_from: changed from
label_checklist_changed_to: to label_checklist_changed_to: to
@ -29,6 +35,10 @@ en:
label_checklist_status: Checklist status label_checklist_status: Checklist status
label_checklist_status_done: Done label_checklist_status_done: Done
label_checklist_status_undone: Undone label_checklist_status_undone: Undone
label_checklist_status: Checklist status
label_checklist_is_default: Default label_checklist_is_default: Default
field_is_for_tracker: Tracker field_is_for_tracker: Tracker
label_checklists_must_be_completed: All checklists of an issue must be done before closing
label_checklist_block_issue_closing: Block issue closing
label_checklist_show_closed: Show closed
label_checklist_hide_closed: Hide closed
label_checklist_new_section: New section

View file

@ -2,3 +2,8 @@
fr: fr:
label_checklist_plural: Liste de Tâches label_checklist_plural: Liste de Tâches
field_checklist: Tâche field_checklist: Tâche
label_checklist_templates: Template de checklists
label_checklist_new_checklist_template: Ajouter un template
field_is_for_tracker:
label_checklist_is_default: Checklist par d faut
field_template_items: Eléments

View file

@ -0,0 +1,45 @@
# encoding: utf-8
# Italian strings go here for Rails i18n
it:
activerecord:
attributes:
checklists:
subject: Checklist soggetto
label_checklist_plural: Checklist
field_checklist: Checklist
label_checklist_save_log: Salva le modifiche nel log delle segnalazioni
label_checklist_done_ratio: Imposta ratio checklist segnalazioni completate
permission_view_checklists: Visualizza la checklist
permission_done_checklists: Elementi checklist completati
permission_edit_checklists: Modifica elementi checklist
label_checklist_template_category_plural: Categorie di modelli
label_checklist_template_category_new: Nuova categoria
field_checklist_template_category: Categoria
label_checklist_templates: Modelli di checklist
label_checklist_new_checklist_template: Nuovo modello di checklist
field_template_items: Elementi del modello
label_checklist_template: Modello di checklist
label_add_checklists_from_template: Aggiungi dal modello
label_checklists_from_template: Dal modello
label_select_template: "- Seleziona modello -"
label_checklist_category_not_specified: "-- Non specificato --"
label_checklists_description: "Sono consentiti più valori (una riga per ciascun valore)"
label_checklist_item: Elemento della checklist
label_checklist_section: Sezione checklist
label_checklist_deleted: Eliminato
label_checklist_changed_from: Modificato da
label_checklist_changed_to: a
label_checklist_added: aggiunto
label_checklist_done: Impostato su Completato
label_checklist_undone: Impostato su Non completato
label_checklist_updated: Elemento della checklist aggiornato
label_checklist_status: Stato della checklist
label_checklist_status_done: Completato
label_checklist_status_undone: Non completato
label_checklist_is_default: Predefinito
field_is_for_tracker: Tracker
label_checklists_must_be_completed: Tutte le liste di controllo di una segnalazione devono essere eseguite prima della chiusura
label_checklist_block_issue_closing: Blocca segnalazione in chiusura
label_checklist_show_closed: Mostra completati
label_checklist_hide_closed: Nascondi completati
label_checklist_new_section: Nuova sezione

View file

@ -1,5 +1,9 @@
# encoding: utf-8 # encoding: utf-8
ru: ru:
activerecord:
attributes:
checklists:
subject: Заголовок чеклиста
label_checklist_plural: Чеклист label_checklist_plural: Чеклист
field_checklist: Чеклист field_checklist: Чеклист
label_checklist_save_log: Сохранять изменения в истории label_checklist_save_log: Сохранять изменения в истории
@ -15,10 +19,12 @@ ru:
field_template_items: Элементы шаблона field_template_items: Элементы шаблона
label_checklist_template: Шаблон чеклистов label_checklist_template: Шаблон чеклистов
label_add_checklists_from_template: Добавить из шаблона label_add_checklists_from_template: Добавить из шаблона
label_checklists_from_template: Из шаблона
label_select_template: "-- Выберите шаблон --" label_select_template: "-- Выберите шаблон --"
label_checklist_category_not_specified: "-- Без категории --" label_checklist_category_not_specified: "-- Без категории --"
label_checklists_description: 'Для ввода нескольких значений вводите по одному на строку' label_checklists_description: 'Для ввода нескольких значений вводите по одному на строку'
label_checklist_item: Пункт чеклиста label_checklist_item: Пункт чеклиста
label_checklist_section: Раздел чеклиста
label_checklist_deleted: удалён label_checklist_deleted: удалён
label_checklist_changed_from: изменён с label_checklist_changed_from: изменён с
label_checklist_changed_to: на label_checklist_changed_to: на
@ -31,3 +37,10 @@ ru:
label_checklist_status_undone: Не выполнен label_checklist_status_undone: Не выполнен
label_checklist_is_default: По умолчанию label_checklist_is_default: По умолчанию
field_is_for_tracker: Трекер field_is_for_tracker: Трекер
label_checklist_show_closed: Показать закрытые
label_checklist_hide_closed: Скрыть закрытые
label_checklist_new_section: Новая секция
label_checklist_block_issue_closing: Запретить закрытие заявки
label_checklists: Чеклист
label_checklists_must_be_completed: Чтобы заявка закрылась, должны быть выполнены все пункты чеклиста
field_checklists: Чеклист

View file

@ -0,0 +1,32 @@
# encoding: utf-8
# Simplified Chinese strings go here for Rails i18n
# Author: Steven.W
# Based on file: en.yml
zh-TW:
label_checklist_plural: Checklist
field_checklist: Checklist
label_checklist_save_log: 保存檢查清單變更到問題日誌
label_checklist_done_ratio: 設置列表完成比率
permission_view_checklists: 查看Checklist
permission_done_checklists: 完成Checklist
permission_edit_checklists: 編輯Checklist
label_checklist_template_category_plural: 範本類別
label_checklist_template_category_new: 新類別
field_checklist_template_category: 類別
label_checklist_templates: 檢查清單範本
label_checklist_new_checklist_template: 新檢查清單範本
field_template_items: 範本項
label_checklist_template: 檢查清單範本
label_add_checklists_from_template: 從範本新建
label_select_template: "-- 選擇範本 --"
label_checklist_category_not_specified: "-- 未指定 --"
label_checklists_description: '允許多重值 (每一行的值)'
label_checklist_item: Checklist item
label_checklist_deleted: 刪除
label_checklist_changed_from: 改變自
label_checklist_changed_to:
label_checklist_added: 添加
label_checklist_done: 設置完成
label_checklist_undone: 設置未完成
label_checklist_updated: Checklist item編輯

View file

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

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>. # along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>.
class CreateChecklists < ActiveRecord::Migration class CreateChecklists < Rails.version < '5.1' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
def self.up def self.up
if ActiveRecord::Base.connection.table_exists? :issue_checklists if ActiveRecord::Base.connection.table_exists? :issue_checklists

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>. # along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>.
class AddTimeStampsToChecklists < ActiveRecord::Migration class AddTimeStampsToChecklists < Rails.version < '5.1' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
def change def change
add_column :checklists, :created_at, :timestamp add_column :checklists, :created_at, :timestamp
add_column :checklists, :updated_at, :timestamp add_column :checklists, :updated_at, :timestamp

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>. # along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>.
class CreateChecklistTemplateCategory < ActiveRecord::Migration class CreateChecklistTemplateCategory < Rails.version < '5.1' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
def self.up def self.up
create_table :checklist_template_categories do |t| create_table :checklist_template_categories do |t|

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>. # along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>.
class CreateChecklistTemplates < ActiveRecord::Migration class CreateChecklistTemplates < Rails.version < '5.1' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
def self.up def self.up
create_table :checklist_templates do |t| create_table :checklist_templates do |t|

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>. # along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>.
class ModifyChecklistSubjectLength < ActiveRecord::Migration class ModifyChecklistSubjectLength < Rails.version < '5.1' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
def self.up def self.up
change_column :checklists, :subject, :string, :limit => 512 change_column :checklists, :subject, :string, :limit => 512
end end

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>. # along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>.
class AddFieldsToChecklistTemplate < ActiveRecord::Migration class AddFieldsToChecklistTemplate < Rails.version < '5.1' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
def self.up def self.up
add_column :checklist_templates, :is_default, :boolean, :default => false add_column :checklist_templates, :is_default, :boolean, :default => false
add_column :checklist_templates, :tracker_id, :integer add_column :checklist_templates, :tracker_id, :integer

View file

@ -0,0 +1,24 @@
# 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/>.
class AddIsSectionToChecklists < (Rails.version < '5.1') ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
def change
add_column :checklists, :is_section, :boolean, default: false
end
end

View file

@ -1,9 +1,61 @@
== Redmine Checklists plugin changelog == Redmine Checklists plugin changelog
Redmine Checklists plugin - managing issue checklists plugin for Redmine Redmine Checklists plugin - managing issue checklists plugin for Redmine
Copyright (C) 2011-2017 RedmineUP Copyright (C) 2011-2020 RedmineUP
http://www.redmineup.com/ http://www.redmineup.com/
== 2020-08-17 v3.1.18
* Added italian locale
* Updated zh-tw locale
* Fixed size() method error
* Fixed initial install error
* Fixed checklist ration recalculate
* Fixed display checklist element with Markdown syntax
* Fixed done ratio recalculate on checklist API update
* Fixed API call journalizing
== 2020-01-31 v3.1.17
* Redmine 4.1 compatibility fixes
* Fixed view permission bug
* Fixed template permissions bug
* Fixed context menu conflicts
* Fixed Agile support
* Fixed checklist copy bug
* Fixed locale bug
* Fixed project copy bug
== 2019-04-29 v3.1.16
* Checklists sections
== 2019-04-15 v3.1.15
* Redmine 4.0.3 support
* Added Hide link for closed items
== 2018-12-20 v3.1.14
* Hotfix for Redmine 4
== 2018-12-18 v3.1.13
* Redmine 4 saving issue fixes
== 2018-11-26 v3.1.12
* German translation update from Tobias Fischer
* Fixed diferent authors changes bug
* Fixed sortable animation bug
== 2018-03-23 v3.1.11
* Redmine 4 support
* Setting for block issues with undone checklists
* Fixed bug with default template
* Fixed email notification bug
== 2017-10-12 v3.1.10 == 2017-10-12 v3.1.10
* Fixed email notification bug * Fixed email notification bug
@ -29,10 +81,10 @@ http://www.redmineup.com/
* Redmine 3.4 support * Redmine 3.4 support
* New checklists filters for issues table * New checklists filters for issues table
* Save log by default * Save log by default
* Chinese translation update * Chinese translation update
* Polish translation update * Polish translation update
* Fixed bug with template editing * Fixed bug with template editing
== 2016-08-15 v3.1.5 == 2016-08-15 v3.1.5

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -20,7 +20,7 @@
require 'redmine' require 'redmine'
require 'redmine_checklists/redmine_checklists' require 'redmine_checklists/redmine_checklists'
CHECKLISTS_VERSION_NUMBER = '3.1.10' CHECKLISTS_VERSION_NUMBER = '3.1.18'.freeze
CHECKLISTS_VERSION_TYPE = "Light version" CHECKLISTS_VERSION_TYPE = "Light version"
Redmine::Plugin.register :redmine_checklists do Redmine::Plugin.register :redmine_checklists do
@ -31,7 +31,7 @@ Redmine::Plugin.register :redmine_checklists do
url 'https://www.redmineup.com/pages/plugins/checklists' url 'https://www.redmineup.com/pages/plugins/checklists'
author_url 'mailto:support@redmineup.com' author_url 'mailto:support@redmineup.com'
requires_redmine :version_or_higher => '2.3' requires_redmine :version_or_higher => '2.6'
settings :default => { settings :default => {
:save_log => true, :save_log => true,
@ -40,9 +40,9 @@ Redmine::Plugin.register :redmine_checklists do
Redmine::AccessControl.map do |map| Redmine::AccessControl.map do |map|
map.project_module :issue_tracking do |map| map.project_module :issue_tracking do |map|
map.permission :view_checklists, {:checklists => [:show, :index]} map.permission :view_checklists, { :checklists => [:show, :index] }
map.permission :done_checklists, {:checklists => :done} map.permission :done_checklists, { :checklists => :done }
map.permission :edit_checklists, {:checklists => [:done, :create, :destroy, :update]} map.permission :edit_checklists, { :checklists => [:done, :create, :destroy, :update] }
end end
end end

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -22,7 +22,7 @@ module RedmineChecklists
class ControllerIssuesHook < Redmine::Hook::ViewListener class ControllerIssuesHook < Redmine::Hook::ViewListener
def controller_issues_edit_after_save(context = {}) def controller_issues_edit_after_save(context = {})
if (Setting.issue_done_ratio == "issue_field") && RedmineChecklists.settings["issue_done_ratio"].to_i > 0 if (Setting.issue_done_ratio == 'issue_field') && RedmineChecklists.issue_done_ratio?
Checklist.recalc_issue_done_ratio(context[:issue].id) Checklist.recalc_issue_done_ratio(context[:issue].id)
end end
end end

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,38 @@
# 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/>.
module RedmineChecklists
module Patches
module ApplicationHelperPatch
def self.included(base) # :nodoc:
base.class_eval do
unloadable # Send unloadable so it will not be unloaded in development
def stocked_reorder_link(object, name = nil, url = {}, method = :post)
Redmine::VERSION.to_s > '3.3' ? reorder_handle(object, :param => name) : reorder_links(name, url, method)
end
end
end
end
end
end
unless ApplicationHelper.included_modules.include?(RedmineChecklists::Patches::ApplicationHelperPatch)
ApplicationHelper.send(:include, RedmineChecklists::Patches::ApplicationHelperPatch)
end

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -17,13 +17,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>. # along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'journal' require_dependency 'journal'
module RedmineChecklists module RedmineChecklists
module Patches module Patches
module JournalPatch module JournalPatch
def self.included(base) # :nodoc: def self.included(base) # :nodoc:
base.send(:include, InstanceMethods) base.send(:include, InstanceMethods)
base.class_eval do base.class_eval do
@ -40,7 +38,7 @@ module RedmineChecklists
(Setting.notified_events.include?('issue_status_updated') && new_status.present?) || (Setting.notified_events.include?('issue_status_updated') && new_status.present?) ||
(Setting.notified_events.include?('issue_priority_updated') && new_value_for('priority_id').present?) (Setting.notified_events.include?('issue_priority_updated') && new_value_for('priority_id').present?)
) )
checklist_email_nootification(self).deliver deliver_checklist_notification
end end
end end
@ -49,17 +47,24 @@ module RedmineChecklists
end end
end end
def checklist_email_nootification(journal) def deliver_checklist_notification
if Redmine::VERSION.to_s >= '4.0'
(notified_watchers | notified_users).each do |user|
Mailer.issue_edit(user, self).deliver
end
else
checklist_email_notification(self).deliver
end
end
def checklist_email_notification(journal)
if Redmine::VERSION.to_s < '2.4' if Redmine::VERSION.to_s < '2.4'
Mailer.issue_edit(journal) Mailer.issue_edit(journal)
else else
to_users = Redmine::VERSION.to_s <= '3.0' ? journal.notified_users : journal.recipients Mailer.issue_edit(journal, journal.notified_users, journal.notified_watchers - journal.notified_users)
cc_users = Redmine::VERSION.to_s <= '3.0' ? journal.notified_watchers - to_users : journal.watcher_recipients - to_users
Mailer.issue_edit(journal, to_users, cc_users)
end end
end end
end end
end end
end end
end end

View file

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

View file

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

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -21,41 +21,46 @@ require_dependency 'issue'
module RedmineChecklists module RedmineChecklists
module Patches module Patches
module IssuePatch module IssuePatch
def self.included(base) # :nodoc: def self.included(base) # :nodoc:
base.send(:include, InstanceMethods) base.send(:include, InstanceMethods)
base.class_eval do base.class_eval do
unloadable # Send unloadable so it will not be unloaded in development unloadable # Send unloadable so it will not be unloaded in development
attr_accessor :old_checklists attr_accessor :old_checklists
attr_accessor :removed_checklist_ids
attr_reader :copied_from attr_reader :copied_from
alias_method_chain :copy, :checklist alias_method :copy_without_checklist, :copy
alias_method :copy, :copy_with_checklist
after_save :copy_subtask_checklists after_save :copy_subtask_checklists
if ActiveRecord::VERSION::MAJOR >= 4 if ActiveRecord::VERSION::MAJOR >= 4
has_many :checklists, lambda { order("#{Checklist.table_name}.position") }, :class_name => "Checklist", :dependent => :destroy, :inverse_of => :issue has_many :checklists, lambda { order("#{Checklist.table_name}.position") }, :class_name => 'Checklist', :dependent => :destroy, :inverse_of => :issue
else else
has_many :checklists, :class_name => "Checklist", :dependent => :destroy, :inverse_of => :issue, has_many :checklists, :class_name => 'Checklist', :dependent => :destroy, :inverse_of => :issue, :order => 'position'
:order => 'position'
end end
accepts_nested_attributes_for :checklists, :allow_destroy => true, :reject_if => proc { |attrs| attrs["subject"].blank? } accepts_nested_attributes_for :checklists, :allow_destroy => true, :reject_if => proc { |attrs| attrs['subject'].blank? }
validate :block_issue_closing_if_checklists_unclosed
safe_attributes 'checklists_attributes', safe_attributes 'checklists_attributes',
:if => lambda {|issue, user| (user.allowed_to?(:done_checklists, issue.project) || :if => lambda { |issue, user| (user.allowed_to?(:done_checklists, issue.project) || user.allowed_to?(:edit_checklists, issue.project)) }
user.allowed_to?(:edit_checklists, issue.project))}
def copy_checklists(arg)
issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg)
issue.checklists.each{ |checklist| Checklist.create(checklist.attributes.except('id','issue_id').merge(:issue => self)) } if issue
end
end end
end end
module InstanceMethods module InstanceMethods
def copy_checklists(arg)
issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg)
if issue
issue.checklists.each do |checklist|
Checklist.create(checklist.attributes.except('id', 'issue_id').merge(issue: self))
end
end
end
def copy_subtask_checklists def copy_subtask_checklists
return if !copy? || parent_id.nil? || checklists.any? return if !copy? || parent_id.nil? || checklists.reload.any?
copy_checklists(@copied_from) copy_checklists(@copied_from)
end end
@ -64,6 +69,23 @@ module RedmineChecklists
copy.copy_checklists(self) copy.copy_checklists(self)
copy copy
end end
def all_checklist_items_is_done?
(checklists - checklists.where(id: removed_checklist_ids)).reject(&:is_section).all?(&:is_done)
end
def need_to_block_issue_closing?
RedmineChecklists.block_issue_closing? &&
checklists.reject(&:is_section).any? &&
status.is_closed? &&
!all_checklist_items_is_done?
end
def block_issue_closing_if_checklists_unclosed
if need_to_block_issue_closing?
errors.add(:checklists, l(:label_checklists_must_be_completed))
end
end
end end
end end
end end

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -32,6 +32,7 @@ module RedmineChecklists
end end
end end
unless IssueQuery.included_modules.include?(RedmineChecklists::Patches::IssueQueryPatch) if (ActiveRecord::Base.connection.tables.include?('queries') rescue false) &&
IssueQuery.included_modules.exclude?(RedmineChecklists::Patches::IssueQueryPatch)
IssueQuery.send(:include, RedmineChecklists::Patches::IssueQueryPatch) IssueQuery.send(:include, RedmineChecklists::Patches::IssueQueryPatch)
end end

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -26,8 +26,9 @@ module RedmineChecklists
base.class_eval do base.class_eval do
unloadable # Send unloadable so it will not be unloaded in development unloadable # Send unloadable so it will not be unloaded in development
alias_method_chain :build_new_issue_from_params, :checklist alias_method :build_new_issue_from_params_without_checklist, :build_new_issue_from_params
before_filter :save_before_state, :only => [:update] alias_method :build_new_issue_from_params, :build_new_issue_from_params_with_checklist
before_action :save_before_state, :only => [:update]
end end
end end
@ -44,6 +45,14 @@ module RedmineChecklists
def save_before_state def save_before_state
@issue.old_checklists = @issue.checklists.to_json @issue.old_checklists = @issue.checklists.to_json
checklists_params = params[:issue].present? && params[:issue][:checklists_attributes].present? ? params[:issue][:checklists_attributes] : {}
@issue.removed_checklist_ids =
if checklists_params.present?
checklists_params = checklists_params.respond_to?(:to_unsafe_hash) ? checklists_params.to_unsafe_hash : checklists_params
checklists_params.map { |_k, v| v['id'].to_i if ['1', 'true'].include?(v['_destroy']) }.compact
else
[]
end
end end
def fill_checklist_attributes def fill_checklist_attributes
@ -60,14 +69,16 @@ module RedmineChecklists
def add_checklists_to_params(checklists) def add_checklists_to_params(checklists)
params[:issue].blank? ? params[:issue] = { :checklists_attributes => {} } : params[:issue][:checklists_attributes] = {} params[:issue].blank? ? params[:issue] = { :checklists_attributes => {} } : params[:issue][:checklists_attributes] = {}
checklists.each_with_index do |checklist_item, index| checklists.each_with_index do |checklist_item, index|
params[:issue][:checklists_attributes][index.to_s] = { :is_done => checklist_item.is_done, params[:issue][:checklists_attributes][index.to_s] = {
:subject => checklist_item.subject, is_done: checklist_item.is_done,
:position => checklist_item.position } subject: checklist_item.subject,
position: checklist_item.position,
is_section: checklist_item.is_section
}
end end
end end
end end
end end
end end
end end

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -26,26 +26,18 @@ module RedmineChecklists
base.class_eval do base.class_eval do
unloadable unloadable
alias_method_chain :details_to_strings, :checklists alias_method :details_to_strings_without_checklists, :details_to_strings
alias_method_chain :render_email_issue_attributes, :checklists if Redmine::VERSION.to_s <= '2.4' && Redmine::VERSION.to_s >= '2.2' alias_method :details_to_strings, :details_to_strings_with_checklists
end end
end end
module InstanceMethods module InstanceMethods
def render_email_issue_attributes_with_checklists(issue, html = false)
journal = issue.journals.order(:id).last
return render_email_issue_attributes_without_checklists(issue, html) unless journal
details = journal.details
return render_email_issue_attributes_without_checklists(issue, html) unless details
checklist_details = details.select{ |x| x.prop_key == 'checklist'}
return render_email_issue_attributes_without_checklists(issue, html) unless checklist_details.any?
return render_email_issue_attributes_without_checklists(issue, html) + details_to_strings_with_checklists(checklist_details, !html).join(html ? "<br/>".html_safe : "\n")
end
def details_to_strings_with_checklists(details, no_html = false, options = {}) def details_to_strings_with_checklists(details, no_html = false, options = {})
details_checklist, details_other = details.partition{ |x| x.prop_key == 'checklist' } details_checklist, details_other = details.partition{ |x| x.prop_key == 'checklist' }
return details_to_strings_without_checklists(details_other, no_html, options) unless User.current.allowed_to?(:view_checklists, @issue.project)
details_checklist.map do |detail| details_checklist.map do |detail|
result = [] result = []
diff = Hash.new([]) diff = Hash.new([])
@ -56,15 +48,19 @@ module RedmineChecklists
diff = JournalChecklistHistory.new(detail.old_value, detail.value).diff diff = JournalChecklistHistory.new(detail.old_value, detail.value).diff
end end
checklist_item_label = lambda do |item|
item[:is_section] ? l(:label_checklist_section) : l(:label_checklist_item)
end
if diff[:done].any? if diff[:done].any?
diff[:done].each do |item| diff[:done].each do |item|
result << "<b>#{ERB::Util.h l(:label_checklist_item)}</b> <input type='checkbox' #{item.is_done ? 'checked' : '' } disabled> <i>#{ERB::Util.h item[:subject]}</i> #{ERB::Util.h l(:label_checklist_done)}" result << "<b>#{ERB::Util.h l(:label_checklist_item)}</b> <input type='checkbox' class='checklist-checkbox' #{item.is_done ? 'checked' : '' } disabled> <i>#{ERB::Util.h item[:subject]}</i> #{ERB::Util.h l(:label_checklist_done)}"
end end
end end
if diff[:undone].any? if diff[:undone].any?
diff[:undone].each do |item| diff[:undone].each do |item|
result << "<b>#{ERB::Util.h l(:label_checklist_item)}</b> <input type='checkbox' #{item.is_done ? 'checked' : '' } disabled> <i>#{ERB::Util.h item[:subject]}</i> #{ERB::Util.h l(:label_checklist_undone)}" result << "<b>#{ERB::Util.h l(:label_checklist_item)}</b> <input type='checkbox' class='checklist-checkbox' #{item.is_done ? 'checked' : '' } disabled> <i>#{ERB::Util.h item[:subject]}</i> #{ERB::Util.h l(:label_checklist_undone)}"
end end
end end
@ -72,8 +68,8 @@ module RedmineChecklists
result = nil if result.blank? result = nil if result.blank?
if result && no_html if result && no_html
result = result.gsub /<\/li><li>/, "\n" result = result.gsub /<\/li><li>/, "\n"
result = result.gsub /<input type='checkbox'[^c^>]*checked[^>]*>/, '[x]' result = result.gsub /<input type='checkbox' class='checklist-checkbox'[^c^>]*checked[^>]*>/, '[x]'
result = result.gsub /<input type='checkbox'[^c^>]*>/, '[ ]' result = result.gsub /<input type='checkbox' class='checklist-checkbox'[^c^>]*>/, '[ ]'
result = result.gsub /<[^>]*>/, '' result = result.gsub /<[^>]*>/, ''
result = CGI.unescapeHTML(result) result = CGI.unescapeHTML(result)
end end

View file

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

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -26,7 +26,8 @@ module RedmineChecklists
base.send(:include, InstanceMethods) base.send(:include, InstanceMethods)
base.class_eval do base.class_eval do
unloadable # Send unloadable so it will not be unloaded in development unloadable # Send unloadable so it will not be unloaded in development
alias_method_chain :copy_issues, :checklist alias_method :copy_issues_without_checklist, :copy_issues
alias_method :copy_issues, :copy_issues_with_checklist
end end
end end
@ -34,7 +35,7 @@ module RedmineChecklists
def copy_issues_with_checklist(project) def copy_issues_with_checklist(project)
copy_issues_without_checklist(project) copy_issues_without_checklist(project)
issues.each{ |issue| issue.copy_checklists(issue.copied_from)} issues.each{ |issue| issue.copy_checklists(issue.copied_from) if issue.reload.checklists.empty? }
end end
end end
end end

View file

@ -1,7 +1,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -18,6 +18,8 @@
# along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>. # along with redmine_checklists. If not, see <http://www.gnu.org/licenses/>.
Rails.configuration.to_prepare do Rails.configuration.to_prepare do
require 'redmine_checklists/patches/compatibility/application_helper_patch'
require 'redmine_checklists/hooks/views_issues_hook' require 'redmine_checklists/hooks/views_issues_hook'
require 'redmine_checklists/hooks/views_layouts_hook' require 'redmine_checklists/hooks/views_layouts_hook'
require 'redmine_checklists/hooks/controller_issues_hook' require 'redmine_checklists/hooks/controller_issues_hook'
@ -33,5 +35,13 @@ Rails.configuration.to_prepare do
end end
module RedmineChecklists module RedmineChecklists
def self.settings() Setting[:plugin_redmine_checklists].blank? ? {} : Setting[:plugin_redmine_checklists] end def self.settings() Setting.plugin_redmine_checklists.blank? ? {} : Setting.plugin_redmine_checklists end
def self.block_issue_closing?
settings['block_issue_closing'].to_i > 0
end
def self.issue_done_ratio?
settings['issue_done_ratio'].to_i > 0
end
end end

View file

@ -1,12 +0,0 @@
#!/bin/bash
RUBY=$1
DB=$2
REDMINE=$3
docker run -t -i -v `pwd`:/var/www/$RUBY/$DB/$REDMINE/plugins/redmine_checklists \
--env RUBY=$1 \
--env DB=$2 \
--env REDMINE=$3 \
--env PLUGIN=redmine_checklists \
redmineup/redmine_checklists \
/root/run_local.sh

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # 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') 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 if ActiveRecord::VERSION::MAJOR >= 4
class RedmineChecklists::IntegrationTest < Redmine::IntegrationTest; end class RedmineChecklists::IntegrationTest < Redmine::IntegrationTest; end
@ -29,7 +62,6 @@ else
end end
class RedmineChecklists::TestCase class RedmineChecklists::TestCase
def self.create_fixtures(fixtures_directory, table_names, class_names = {}) def self.create_fixtures(fixtures_directory, table_names, class_names = {})
if ActiveRecord::VERSION::MAJOR >= 4 if ActiveRecord::VERSION::MAJOR >= 4
ActiveRecord::FixtureSet.create_fixtures(fixtures_directory, table_names, class_names = {}) ActiveRecord::FixtureSet.create_fixtures(fixtures_directory, table_names, class_names = {})
@ -39,6 +71,11 @@ class RedmineChecklists::TestCase
end end
def self.prepare 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| Role.find(1, 2, 3, 4).each do |r|
r.permissions << :edit_checklists r.permissions << :edit_checklists
r.save r.save
@ -53,7 +90,5 @@ class RedmineChecklists::TestCase
r.permissions << :manage_checklist_templates r.permissions << :manage_checklist_templates
r.save r.save
end end
end end
end end

View file

@ -3,7 +3,7 @@
# This file is a part of Redmine Checklists (redmine_checklists) plugin, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify
@ -46,8 +46,7 @@ class ChecklistTest < ActiveSupport::TestCase
:journal_details, :journal_details,
:queries :queries
RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/', RedmineChecklists::TestCase.create_fixtures(Redmine::Plugin.find(:redmine_checklists).directory + '/test/fixtures/', [:checklists])
[:checklists])
def setup def setup
RedmineChecklists::TestCase.prepare RedmineChecklists::TestCase.prepare
Setting.default_language = 'en' Setting.default_language = 'en'
@ -56,11 +55,8 @@ class ChecklistTest < ActiveSupport::TestCase
:status_id => 1, :priority => IssuePriority.first, :status_id => 1, :priority => IssuePriority.first,
:subject => 'Invoice Issue 1') :subject => 'Invoice Issue 1')
@checklist_1 = Checklist.create(:subject => 'TEST1', :position => 1, :issue => @issue_1) @checklist_1 = Checklist.create(:subject => 'TEST1', :position => 1, :issue => @issue_1)
end end
test "should save checklist" do test "should save checklist" do
assert @checklist_1.save, "Checklist save error" assert @checklist_1.save, "Checklist save error"
end end
@ -90,4 +86,53 @@ class ChecklistTest < ActiveSupport::TestCase
assert_equal "[x] #{@checklist_1.subject}", @checklist_1.info, "Helper info broken" assert_equal "[x] #{@checklist_1.subject}", @checklist_1.info, "Helper info broken"
end 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 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, # This file is a part of Redmine Checklists (redmine_checklists) plugin,
# issue checklists management plugin for Redmine # issue checklists management plugin for Redmine
# #
# Copyright (C) 2011-2017 RedmineUP # Copyright (C) 2011-2020 RedmineUP
# http://www.redmineup.com/ # http://www.redmineup.com/
# #
# redmine_checklists is free software: you can redistribute it and/or modify # redmine_checklists is free software: you can redistribute it and/or modify