Merge pull request #5457 from opf/fix/list_cf_export

[ci skip]
pull/5463/head
Oliver Günther 8 years ago committed by GitHub
commit 4fe4fc4d85
  1. 32
      app/controllers/time_entries/reports_controller.rb
  2. 36
      app/helpers/custom_fields_helper.rb
  3. 6
      app/models/custom_field.rb
  4. 56
      app/models/custom_value.rb
  5. 4
      app/models/custom_value/ar_object_strategy.rb
  6. 9
      app/models/custom_value/bool_strategy.rb
  7. 7
      app/models/custom_value/date_strategy.rb
  8. 7
      app/models/custom_value/float_strategy.rb
  9. 7
      app/models/custom_value/format_strategy.rb
  10. 8
      app/models/work_package/pdf_export/work_package_list_to_pdf.rb
  11. 2
      app/views/custom_fields/_tab.html.erb
  12. 1
      app/views/time_entries/reports/_report_criteria.html.erb
  13. 76
      config/initializers/custom_field_format.rb
  14. 2
      lib/custom_field_form_builder.rb
  15. 3
      lib/open_project.rb
  16. 65
      lib/open_project/custom_field_format.rb
  17. 6
      lib/open_project/journal_formatter/custom_field.rb
  18. 41
      spec/helpers/custom_fields_helper_spec.rb
  19. 2
      spec/lib/api/v3/utilities/custom_field_injector_spec.rb
  20. 66
      spec/lib/journal_formatter/custom_field_spec.rb
  21. 41
      spec/lib/redmine/custom_field_format_spec.rb
  22. 59
      spec/models/custom_value/bool_strategy_spec.rb
  23. 37
      spec/models/custom_value/date_strategy_spec.rb
  24. 43
      spec/models/custom_value/float_strategy_spec.rb
  25. 28
      spec/models/custom_value/int_strategy_spec.rb
  26. 46
      spec/models/custom_value/list_strategy_spec.rb
  27. 37
      spec/models/custom_value/string_strategy_spec.rb
  28. 51
      spec/models/custom_value/user_strategy_spec.rb
  29. 61
      spec/models/custom_value/version_strategy_spec.rb
  30. 2
      spec_legacy/unit/custom_field_user_format_spec.rb

@ -135,27 +135,39 @@ class TimeEntries::ReportsController < ApplicationController
# Add list and boolean custom fields as available criterias
custom_fields = (@project.nil? ? WorkPackageCustomField.for_all : @project.all_work_package_custom_fields)
custom_fields.select { |cf| %w(list bool).include? cf.field_format }.each do |cf|
@available_criterias["cf_#{cf.id}"] = { sql: "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'WorkPackage' AND c.customized_id = #{WorkPackage.table_name}.id)",
format: cf.field_format,
label: cf.name }
end if @project
if @project
custom_fields.select { |cf| %w(list bool).include? cf.field_format }.each do |cf|
@available_criterias["cf_#{cf.id}"] = { sql: "(SELECT c.value FROM #{CustomValue.table_name} c
WHERE c.custom_field_id = #{cf.id}
AND c.customized_type = 'WorkPackage'
AND c.customized_id = #{WorkPackage.table_name}.id)",
format: cf,
label: cf.name }
end
end
# Add list and boolean time entry custom fields
TimeEntryCustomField.all.select { |cf| %w(list bool).include? cf.field_format }.each do |cf|
@available_criterias["cf_#{cf.id}"] = { sql: "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'TimeEntry' AND c.customized_id = #{TimeEntry.table_name}.id)",
format: cf.field_format,
@available_criterias["cf_#{cf.id}"] = { sql: "(SELECT c.value FROM #{CustomValue.table_name} c
WHERE c.custom_field_id = #{cf.id}
AND c.customized_type = 'TimeEntry'
AND c.customized_id = #{TimeEntry.table_name}.id)",
format: cf,
label: cf.name }
end
# Add list and boolean time entry activity custom fields
TimeEntryActivityCustomField.all.select { |cf| %w(list bool).include? cf.field_format }.each do |cf|
@available_criterias["cf_#{cf.id}"] = { sql: "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Enumeration' AND c.customized_id = #{TimeEntry.table_name}.activity_id)",
format: cf.field_format,
@available_criterias["cf_#{cf.id}"] = { sql: "(SELECT c.value FROM #{CustomValue.table_name} c
WHERE c.custom_field_id = #{cf.id}
AND c.customized_type = 'Enumeration'
AND c.customized_id = #{TimeEntry.table_name}.activity_id)",
format: cf,
label: cf.name }
end
call_hook(:controller_timelog_available_criterias, available_criterias: @available_criterias, project: @project)
call_hook(:controller_timelog_available_criterias, available_criterias: @available_criterias, project: @project)
@available_criterias
end

@ -1,4 +1,5 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
@ -47,7 +48,7 @@ module CustomFieldsHelper
field_name = "#{name}[custom_field_values][#{custom_field.id}]"
field_id = "#{name}_custom_field_values_#{custom_field.id}"
field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
field_format = OpenProject::CustomFieldFormat.find_by_name(custom_field.field_format)
tag = case field_format.try(:edit_as)
when 'date'
@ -114,7 +115,7 @@ module CustomFieldsHelper
def custom_field_tag_for_bulk_edit(name, custom_field, project=nil)
field_name = "#{name}[custom_field_values][#{custom_field.id}]"
field_id = "#{name}_custom_field_values_#{custom_field.id}"
field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
field_format = OpenProject::CustomFieldFormat.find_by_name(custom_field.field_format)
case field_format.try(:edit_as)
when 'date'
styled_text_field_tag(field_name, '', id: field_id, size: 10) +
@ -135,27 +136,32 @@ module CustomFieldsHelper
# Return a string used to display a custom value
def show_value(custom_value)
return '' unless custom_value
format_value(custom_value.value, custom_value.custom_field.field_format)
custom_value.formatted_value
end
# Return a string used to display a custom value
def format_value(value, field_format)
Redmine::CustomFieldFormat.format_value(value, field_format) # Proxy
def format_value(value, custom_field)
custom_value = CustomValue.new(custom_field: custom_field,
value: value)
custom_value.formatted_value
end
# Return an array of custom field formats which can be used in select_tag
def custom_field_formats_for_select(custom_field)
Redmine::CustomFieldFormat.as_select(custom_field.class.customized_class.name)
OpenProject::CustomFieldFormat
.all_for_field(custom_field)
.sort_by(&:order)
.map do |custom_field_format|
[label_for_custom_field_format(custom_field_format.name), custom_field_format.name]
end
end
# Renders the custom_values in api views
def render_api_custom_values(custom_values, api)
api.array :custom_fields do
custom_values.each do |custom_value|
api.custom_field id: custom_value.custom_field_id, name: custom_value.custom_field.name do
api.value custom_value.value
end
end
end unless custom_values.empty?
def label_for_custom_field_format(format_string)
format = OpenProject::CustomFieldFormat.find_by_name(format_string)
if format
format.label.is_a?(Proc) ? format.label.call : I18n.t(format.label)
end
end
end

@ -49,7 +49,7 @@ class CustomField < ActiveRecord::Base
errors.add(:name, :taken) if name.in?(taken_names)
end
validates_inclusion_of :field_format, in: Redmine::CustomFieldFormat.available_formats
validates_inclusion_of :field_format, in: OpenProject::CustomFieldFormat.available_formats
validate :validate_default_value
@ -96,6 +96,10 @@ class CustomField < ActiveRecord::Base
end
end
def required?
is_required?
end
def possible_values_options(obj = nil)
case field_format
when 'user', 'version'

@ -1,4 +1,5 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
@ -28,18 +29,6 @@
#++
class CustomValue < ActiveRecord::Base
FORMAT_STRATEGIES = {
'string' => CustomValue::StringStrategy,
'text' => CustomValue::StringStrategy,
'int' => CustomValue::IntStrategy,
'float' => CustomValue::FloatStrategy,
'date' => CustomValue::DateStrategy,
'bool' => CustomValue::BoolStrategy,
'user' => CustomValue::UserStrategy,
'version' => CustomValue::VersionStrategy,
'list' => CustomValue::ListStrategy
}.freeze
belongs_to :custom_field
belongs_to :customized, polymorphic: true
@ -48,23 +37,16 @@ class CustomValue < ActiveRecord::Base
validate :validate_type_of_value
validate :validate_length_of_value
# returns the value of this custom value, but converts it according to the field_format
# of the custom field beforehand
def typed_value
strategy.typed_value
end
def editable?
custom_field.editable?
end
def visible?
custom_field.visible?
end
delegate :typed_value,
:formatted_value,
to: :strategy
def required?
custom_field.is_required?
end
delegate :editable?,
:visible?,
:required?,
:max_length,
:min_length,
to: :custom_field
def to_s
value.to_s
@ -79,7 +61,7 @@ class CustomValue < ActiveRecord::Base
protected
def validate_presence_of_required_value
errors.add(:value, :blank) if custom_field.is_required? && !strategy.value_present?
errors.add(:value, :blank) if custom_field.required? && !strategy.value_present?
end
def validate_format_of_value
@ -98,15 +80,23 @@ class CustomValue < ActiveRecord::Base
end
def validate_length_of_value
if value.present? && custom_field.min_length.present? && custom_field.max_length.present?
errors.add(:value, :too_short, count: custom_field.min_length) if custom_field.min_length > 0 and value.length < custom_field.min_length
errors.add(:value, :too_long, count: custom_field.max_length) if custom_field.max_length > 0 and value.length > custom_field.max_length
if value.present? && (min_length.present? || max_length.present?)
validate_min_length_of_value
validate_max_length_of_value
end
end
private
def validate_min_length_of_value
errors.add(:value, :too_short, count: min_length) if min_length > 0 && value.length < min_length
end
def validate_max_length_of_value
errors.add(:value, :too_long, count: max_length) if max_length > 0 && value.length > max_length
end
def strategy
@strategy ||= FORMAT_STRATEGIES[custom_field.field_format].new(self)
@strategy ||= OpenProject::CustomFieldFormat.find_by_name(custom_field.field_format).formatter.new(self)
end
end

@ -39,6 +39,10 @@ class CustomValue::ARObjectStrategy < CustomValue::FormatStrategy
end
end
def formatted_value
typed_value.to_s
end
def parse_value(val)
if val.is_a?(ar_class)
self.memoized_typed_value = val

@ -1,4 +1,5 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
@ -41,6 +42,11 @@ class CustomValue::BoolStrategy < CustomValue::FormatStrategy
ActiveRecord::Type::Boolean.new.cast(value)
end
def formatted_value
is_true = ActiveRecord::Type::Boolean.new.cast(value)
I18n.t(is_true ? :general_text_Yes : :general_text_No)
end
def parse_value(val)
parsed_val = if !present?(val)
nil
@ -53,8 +59,7 @@ class CustomValue::BoolStrategy < CustomValue::FormatStrategy
super(parsed_val)
end
def validate_type_of_value
end
def validate_type_of_value; end
private

@ -1,4 +1,5 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
@ -34,6 +35,12 @@ class CustomValue::DateStrategy < CustomValue::FormatStrategy
end
end
def formatted_value
format_date(value.to_date)
rescue
value.to_s
end
def validate_type_of_value
return nil if value.is_a? Date

@ -1,4 +1,5 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
@ -28,12 +29,18 @@
#++
class CustomValue::FloatStrategy < CustomValue::FormatStrategy
include ActionView::Helpers::NumberHelper
def typed_value
unless value.blank?
value.to_f
end
end
def formatted_value
number_with_delimiter(value.to_s)
end
def validate_type_of_value
Kernel.Float(value)
nil

@ -1,4 +1,5 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
@ -45,6 +46,12 @@ class CustomValue::FormatStrategy
raise 'SubclassResponsibility'
end
# Returns the value of the CustomValue formatted to a string
# representation.
def formatted_value
value.to_s
end
# Parses the value to
# 1) have a unified representation for different inputs
# 2) memoize typed values (if the subclass descides to do so

@ -171,11 +171,11 @@ class WorkPackage::PdfExport::WorkPackageListToPdf
end
def make_custom_field_value(work_package, column)
value = work_package
.custom_values
.detect { |v| v.custom_field_id == column.custom_field.id }
values = work_package
.custom_values
.select { |v| v.custom_field_id == column.custom_field.id }
pdf.make_cell show_value(value),
pdf.make_cell values.map(&:formatted_value).join(', '),
padding: cell_padding
end
end

@ -107,7 +107,7 @@ See doc/COPYRIGHT.rdoc for more details.
<% (@custom_fields_by_type[tab[:name]] || []).sort.each do |custom_field| -%>
<tr>
<td><%= link_to h(custom_field.name), edit_custom_field_path(custom_field), lang: custom_field.name_locale %></td>
<td><%= Redmine::CustomFieldFormat.label_for(custom_field.field_format) %></td>
<td><%= label_for_custom_field_format(custom_field.field_format) %></td>
<td><%= checked_image custom_field.is_required? %></td>
<% if tab[:name] == 'WorkPackageCustomField' %>
<td><%= checked_image custom_field.is_for_all? %></td>

@ -28,6 +28,7 @@ See doc/COPYRIGHT.rdoc for more details.
++#%>
<% @hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| %>
<% hours_for_value = select_hours(hours, criterias[level], value) -%>
<% next if hours_for_value.empty? -%>
<tr class="<%= 'last-level' unless criterias.length > level+1 %>">

@ -1,4 +1,5 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
@ -27,38 +28,45 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
Redmine::CustomFieldFormat.map do |fields|
fields.register Redmine::CustomFieldFormat.new('string',
label: :label_string,
order: 1)
fields.register Redmine::CustomFieldFormat.new('text',
label: :label_text,
order: 2)
fields.register Redmine::CustomFieldFormat.new('int',
label: :label_integer,
order: 3)
fields.register Redmine::CustomFieldFormat.new('float',
label: :label_float,
order: 4)
fields.register Redmine::CustomFieldFormat.new('list',
label: :label_list,
order: 5)
fields.register Redmine::CustomFieldFormat.new('date',
label: :label_date,
order: 6)
fields.register Redmine::CustomFieldFormat.new('bool',
label: :label_boolean,
order: 7)
fields.register Redmine::CustomFieldFormat.new('user',
label: Proc.new { User.model_name.human },
only: %w(WorkPackage TimeEntry
Version Project),
edit_as: 'list',
order: 8)
fields.register Redmine::CustomFieldFormat.new('version',
label: Proc.new { Version.model_name.human },
only: %w(WorkPackage TimeEntry
Version Project),
edit_as: 'list',
order: 9)
OpenProject::CustomFieldFormat.map do |fields|
fields.register OpenProject::CustomFieldFormat.new('string',
label: :label_string,
order: 1)
fields.register OpenProject::CustomFieldFormat.new('text',
label: :label_text,
order: 2)
fields.register OpenProject::CustomFieldFormat.new('int',
label: :label_integer,
order: 3,
formatter: CustomValue::IntStrategy)
fields.register OpenProject::CustomFieldFormat.new('float',
label: :label_float,
order: 4,
formatter: CustomValue::FloatStrategy)
fields.register OpenProject::CustomFieldFormat.new('list',
label: :label_list,
order: 5,
formatter: CustomValue::ListStrategy)
fields.register OpenProject::CustomFieldFormat.new('date',
label: :label_date,
order: 6,
formatter: CustomValue::DateStrategy)
fields.register OpenProject::CustomFieldFormat.new('bool',
label: :label_boolean,
order: 7,
formatter: CustomValue::BoolStrategy)
fields.register OpenProject::CustomFieldFormat.new('user',
label: Proc.new { User.model_name.human },
only: %w(WorkPackage TimeEntry
Version Project),
edit_as: 'list',
order: 8,
formatter: CustomValue::UserStrategy)
fields.register OpenProject::CustomFieldFormat.new('version',
label: Proc.new { Version.model_name.human },
only: %w(WorkPackage TimeEntry
Version Project),
edit_as: 'list',
order: 9,
formatter: CustomValue::VersionStrategy)
end

@ -54,7 +54,7 @@ class CustomFieldFormBuilder < TabularFormBuilder
name: custom_field_field_name,
id: custom_field_field_id)
field_format = Redmine::CustomFieldFormat.find_by_name(object.custom_field.field_format)
field_format = OpenProject::CustomFieldFormat.find_by_name(object.custom_field.field_format)
case field_format.try(:edit_as)
when 'date'

@ -1,4 +1,5 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
@ -30,7 +31,7 @@
require 'redmine/menu_manager'
require 'redmine/activity'
require 'redmine/search'
require 'redmine/custom_field_format'
require 'open_project/custom_field_format'
require 'redmine/mime_type'
require 'redmine/core_ext'
require 'open_project/design'

@ -1,4 +1,5 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
@ -27,50 +28,22 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
module Redmine
module OpenProject
class CustomFieldFormat
include Redmine::I18n
include ActionView::Helpers::NumberHelper
cattr_accessor :available
@@available = {}
attr_accessor :name, :order, :label, :edit_as, :class_names
attr_accessor :name, :order, :label, :edit_as, :class_names, :formatter
def initialize(name, label:, order:, edit_as: name, only: nil)
def initialize(name, label:, order:, edit_as: name, only: nil, formatter: CustomValue::StringStrategy)
self.name = name
self.label = label
self.order = order
self.edit_as = edit_as
self.class_names = only
end
def format(value)
send "format_as_#{name}", value
end
def format_as_date(value)
format_date(value.to_date); rescue; value end
def format_as_bool(value)
is_true = ActiveRecord::Type::Boolean.new.cast(value)
l(is_true ? :general_text_Yes : :general_text_No)
end
['string', 'text', 'int', 'list'].each do |name|
define_method("format_as_#{name}") {|value|
return value.to_s
}
end
def format_as_float(value)
number_with_delimiter(value.to_s)
end
['user', 'version'].each do |name|
define_method("format_as_#{name}") {|value|
return value.blank? ? '' : name.classify.constantize.find_by(id: value.to_i).to_s
}
self.formatter = formatter
end
class << self
@ -91,30 +64,12 @@ module Redmine
@@available[name.to_s]
end
def label_for(name)
format = @@available[name.to_s]
format.label.is_a?(Proc) ? format.label.call : l(format.label) if format
end
# Return an array of custom field formats which can be used in select_tag
def as_select(class_name = nil)
fields = @@available.values
fields = fields.select { |field| field.class_names.nil? || field.class_names.include?(class_name) }
fields.sort {|a, b|
a.order <=> b.order
}.map {|custom_field_format|
[label_for(custom_field_format.name), custom_field_format.name]
}
end
def format_value(value, field_format)
return '' unless value && !value.empty?
def all_for_field(custom_field)
class_name = custom_field.class.customized_class.name
if format_type = find_by_name(field_format)
format_type.format(value)
else
value
end
available
.values
.select { |field| field.class_names.nil? || field.class_names.include?(class_name) }
end
end
end

@ -71,8 +71,8 @@ class OpenProject::JournalFormatter::CustomField < ::JournalFormatter::Base
end
def format_single(custom_field, values)
old_value = format_value(values.first, custom_field.field_format) if values.first
value = format_value(values.last, custom_field.field_format) if values.last
old_value = format_value(values.first, custom_field) if values.first
value = format_value(values.last, custom_field) if values.last
[old_value, value]
end
@ -89,7 +89,7 @@ class OpenProject::JournalFormatter::CustomField < ::JournalFormatter::Base
String(values)
.split(",")
.map(&:strip)
.map { |value| format_value value, custom_field.field_format }
.map { |value| format_value value, custom_field }
.join(", ")
.presence
end

@ -1,41 +0,0 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe CustomFieldsHelper, type: :helper do
include OpenProject::FormTagHelper
include CustomFieldsHelper
include Redmine::I18n
it 'should format boolean value' do
I18n.locale = 'en'
expect(format_value('1', 'bool')).to eq 'Yes'
expect(format_value('0', 'bool')).to eq 'No'
end
end

@ -42,7 +42,7 @@ describe ::API::V3::Utilities::CustomFieldInjector do
describe 'TYPE_MAP' do
it 'supports all available formats' do
Redmine::CustomFieldFormat.available_formats.each do |format|
OpenProject::CustomFieldFormat.available_formats.each do |format|
expect(described_class::TYPE_MAP[format]).not_to be_nil
end
end

@ -45,41 +45,41 @@ describe OpenProject::JournalFormatter::CustomField do
describe '#render' do
describe 'WITH the first value beeing nil, and the second a valid value as string' do
let(:values) { [nil, '1'] }
let(:formatted_value) { format_value(values.last, custom_field.field_format) }
let(:formatted_value) { format_value(values.last, custom_field) }
let(:expected) {
let(:expected) do
I18n.t(:text_journal_set_to,
label: "<strong>#{custom_field.name}</strong>",
value: "<i title=\"#{formatted_value}\">#{formatted_value}</i>")
}
end
it { expect(instance.render(key, values)).to eq(expected) }
end
describe 'WITH the first value beeing a valid value as a string, and the second beeing a valid value as a string' do
let(:values) { ['0', '1'] }
let(:old_formatted_value) { format_value(values.first, custom_field.field_format) }
let(:new_formatted_value) { format_value(values.last, custom_field.field_format) }
let(:old_formatted_value) { format_value(values.first, custom_field) }
let(:new_formatted_value) { format_value(values.last, custom_field) }
let(:expected) {
let(:expected) do
I18n.t(:text_journal_changed,
label: "<strong>#{custom_field.name}</strong>",
old: "<i title=\"#{old_formatted_value}\">#{old_formatted_value}</i>",
new: "<i title=\"#{new_formatted_value}\">#{new_formatted_value}</i>")
}
end
it { expect(instance.render(key, values)).to eq(expected) }
end
describe 'WITH the first value beeing a valid value as a string, and the second beeing nil' do
let(:values) { ['0', nil] }
let(:formatted_value) { format_value(values.first, custom_field.field_format) }
let(:formatted_value) { format_value(values.first, custom_field) }
let(:expected) {
let(:expected) do
I18n.t(:text_journal_deleted,
label: "<strong>#{custom_field.name}</strong>",
old: "<strike><i title=\"#{formatted_value}\">#{formatted_value}</i></strike>")
}
end
it { expect(instance.render(key, values)).to eq(expected) }
end
@ -88,11 +88,11 @@ describe OpenProject::JournalFormatter::CustomField do
WITH no html requested" do
let(:values) { [nil, '1'] }
let(:expected) {
let(:expected) do
I18n.t(:text_journal_set_to,
label: "#{custom_field.name}",
value: "#{ format_value(values.last, custom_field.field_format) }")
}
label: custom_field.name,
value: format_value(values.last, custom_field))
end
it { expect(instance.render(key, values, no_html: true)).to eq(expected) }
end
@ -101,12 +101,12 @@ describe OpenProject::JournalFormatter::CustomField do
WITH no html requested" do
let(:values) { ['0', '1'] }
let(:expected) {
let(:expected) do
I18n.t(:text_journal_changed,
label: "#{custom_field.name}",
old: "#{ format_value(values.first, custom_field.field_format) }",
new: "#{ format_value(values.last, custom_field.field_format) }")
}
label: custom_field.name,
old: format_value(values.first, custom_field),
new: format_value(values.last, custom_field))
end
it { expect(instance.render(key, values, no_html: true)).to eq(expected) }
end
@ -115,11 +115,11 @@ describe OpenProject::JournalFormatter::CustomField do
WITH no html requested" do
let(:values) { ['0', nil] }
let(:expected) {
let(:expected) do
I18n.t(:text_journal_deleted,
label: "#{custom_field.name}",
old: "#{ format_value(values.first, custom_field.field_format) }")
}
label: custom_field.name,
old: format_value(values.first, custom_field))
end
it { expect(instance.render(key, values, no_html: true)).to eq(expected) }
end
@ -129,11 +129,11 @@ describe OpenProject::JournalFormatter::CustomField do
let(:values) { [nil, '1'] }
let(:key) { 'custom_values0' }
let(:expected) {
let(:expected) do
I18n.t(:text_journal_set_to,
label: "<strong>#{I18n.t(:label_deleted_custom_field)}</strong>",
value: "<i title=\"#{values.last}\">#{ values.last }</i>")
}
value: "<i title=\"#{values.last}\">#{values.last}</i>")
end
it { expect(instance.render(key, values)).to eq(expected) }
end
@ -143,12 +143,12 @@ describe OpenProject::JournalFormatter::CustomField do
let(:values) { ['0', '1'] }
let(:key) { 'custom_values0' }
let(:expected) {
let(:expected) do
I18n.t(:text_journal_changed,
label: "<strong>#{I18n.t(:label_deleted_custom_field)}</strong>",
old: "<i title=\"#{values.first}\">#{ values.first }</i>",
new: "<i title=\"#{values.last}\">#{ values.last }</i>")
}
old: "<i title=\"#{values.first}\">#{values.first}</i>",
new: "<i title=\"#{values.last}\">#{values.last}</i>")
end
it { expect(instance.render(key, values)).to eq(expected) }
end
@ -158,11 +158,11 @@ describe OpenProject::JournalFormatter::CustomField do
let(:values) { ['0', nil] }
let(:key) { 'custom_values0' }
let(:expected) {
let(:expected) do
I18n.t(:text_journal_deleted,
label: "<strong>#{I18n.t(:label_deleted_custom_field)}</strong>",
old: "<strike><i title=\"#{values.first}\">#{ values.first }</i></strike>")
}
old: "<strike><i title=\"#{values.first}\">#{values.first}</i></strike>")
end
it { expect(instance.render(key, values)).to eq(expected) }
end

@ -1,41 +0,0 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe Redmine::CustomFieldFormat do
let(:instance) { described_class.new 'test', label: 'blubs', order: '1' }
describe '#format_value' do
it 'returns a localized float' do
I18n.with_locale(:de) do
expect(instance.format_as_float('5.67')).to eql '5,67'
end
end
end
end

@ -29,6 +29,7 @@
require 'spec_helper'
describe CustomValue::BoolStrategy do
let(:instance) { described_class.new(custom_value) }
let(:custom_value) do
double('CustomValue',
value: value)
@ -64,7 +65,7 @@ describe CustomValue::BoolStrategy do
end
describe '#typed_value' do
subject { described_class.new(custom_value).typed_value }
subject { instance.typed_value }
context 'value corresponds to true' do
let(:value) { '1' }
@ -97,8 +98,60 @@ describe CustomValue::BoolStrategy do
end
end
describe '#formatted_value' do
subject { instance.formatted_value }
context 'value is present string' do
let(:value) { '1' }
it 'is the true string' do
is_expected.to eql I18n.t(:general_text_Yes)
end
end
context 'value is zero string' do
let(:value) { '0' }
it 'is the false string' do
is_expected.to eql I18n.t(:general_text_No)
end
end
context 'value is true' do
let(:value) { true }
it 'is the true string' do
is_expected.to eql I18n.t(:general_text_Yes)
end
end
context 'value is false' do
let(:value) { false }
it 'is the false string' do
is_expected.to eql I18n.t(:general_text_No)
end
end
context 'value is nil' do
let(:value) { nil }
it 'is the false string' do
is_expected.to eql I18n.t(:general_text_No)
end
end
context 'value is blank' do
let(:value) { '' }
it 'is the false string' do
is_expected.to eql I18n.t(:general_text_No)
end
end
end
describe '#validate_type_of_value' do
subject { described_class.new(custom_value).validate_type_of_value }
subject { instance.validate_type_of_value }
context 'value corresponds to true' do
let(:value) { '1' }
@ -130,7 +183,7 @@ describe CustomValue::BoolStrategy do
end
describe '#parse_value' do
subject { described_class.new(custom_value).parse_value(value) }
subject { instance.parse_value(value) }
ActiveRecord::Type::Boolean::FALSE_VALUES.each do |falsey_value|
context "for #{falsey_value}" do

@ -29,13 +29,14 @@
require 'spec_helper'
describe CustomValue::DateStrategy do
let(:custom_value) {
let(:instance) { described_class.new(custom_value) }
let(:custom_value) do
double('CustomValue',
value: value)
}
end
describe '#typed_value' do
subject { described_class.new(custom_value).typed_value }
subject { instance.typed_value }
context 'value is some date string' do
let(:value) { '2015-01-03' }
@ -53,8 +54,36 @@ describe CustomValue::DateStrategy do
end
end
describe '#formatted_value' do
subject { instance.formatted_value }
context 'value is some date string' do
let(:value) { '2015-01-03' }
it 'is the date' do
is_expected.to eql value
end
end
context 'value is blank' do
let(:value) { '' }
it 'is a blank string' do
is_expected.to eql value
end
end
context 'value is nil' do
let(:value) { nil }
it 'is a blank string' do
is_expected.to eql ''
end
end
end
describe '#validate_type_of_value' do
subject { described_class.new(custom_value).validate_type_of_value }
subject { instance.validate_type_of_value }
context 'value is valid date string' do
let(:value) { '2015-01-03' }

@ -29,13 +29,14 @@
require 'spec_helper'
describe CustomValue::FloatStrategy do
let(:custom_value) {
let(:instance) { described_class.new(custom_value) }
let(:custom_value) do
double('CustomValue',
value: value)
}
end
describe '#typed_value' do
subject { described_class.new(custom_value).typed_value }
subject { instance.typed_value }
context 'value is some float string' do
let(:value) { '3.14' }
@ -53,8 +54,42 @@ describe CustomValue::FloatStrategy do
end
end
describe '#formatted_value' do
subject { instance.formatted_value }
context 'value is some float string' do
let(:value) { '3.14' }
it 'is the float string' do
is_expected.to eql value
end
it 'is localized' do
I18n.with_locale(:de) do
is_expected.to eql '3,14'
end
end
end
context 'value is blank' do
let(:value) { '' }
it 'is a blank string' do
is_expected.to eql value
end
end
context 'value is nil' do
let(:value) { nil }
it 'is a blank string' do
is_expected.to eql ''
end
end
end
describe '#validate_type_of_value' do
subject { described_class.new(custom_value).validate_type_of_value }
subject { instance.validate_type_of_value }
context 'value is float string in decimal notation' do
let(:value) { '3.14' }

@ -29,13 +29,14 @@
require 'spec_helper'
describe CustomValue::IntStrategy do
let(:custom_value) {
let(:instance) { described_class.new(custom_value) }
let(:custom_value) do
double('CustomValue',
value: value)
}
end
describe '#typed_value' do
subject { described_class.new(custom_value).typed_value }
subject { instance.typed_value }
context 'value is some float string' do
let(:value) { '10' }
@ -53,8 +54,27 @@ describe CustomValue::IntStrategy do
end
end
describe '#formatted_value' do
subject { instance.typed_value }
context 'value is some int string' do
let(:value) { '10' }
it { is_expected.to eql(10) }
end
context 'value is blank' do
let(:value) { '' }
it { is_expected.to be_nil }
end
context 'value is nil' do
let(:value) { nil }
it { is_expected.to be_nil }
end
end
describe '#validate_type_of_value' do
subject { described_class.new(custom_value).validate_type_of_value }
subject { instance.validate_type_of_value }
context 'value is positive int string' do
let(:value) { '10' }

@ -29,6 +29,7 @@
require 'spec_helper'
describe CustomValue::ListStrategy do
let(:instance) { described_class.new(custom_value) }
let(:custom_field) { FactoryGirl.create :list_wp_custom_field }
let(:custom_value) do
double("CustomField", value: value, custom_field: custom_field, customized: customized)
@ -37,7 +38,7 @@ describe CustomValue::ListStrategy do
let(:customized) { double('customized') }
describe '#parse_value/#typed_value' do
subject { described_class.new(custom_value) }
subject { instance }
context 'with a CustomOption' do
let(:value) { custom_field.custom_options.first }
@ -89,8 +90,49 @@ describe CustomValue::ListStrategy do
end
end
describe '#formatted_value' do
subject { instance.formatted_value }
context 'with a CustomOption' do
let(:value) { custom_field.custom_options.first }
it 'is the custom option to_s (without db access)' do
instance.parse_value(value)
expect(CustomOption)
.to_not receive(:where)
expect(subject).to eql value.to_s
end
end
context 'with an id string' do
let(:value) { custom_field.custom_options.first.id.to_s }
it 'is the custom option to_s (with db access)' do
expect(subject).to eql custom_field.custom_options.first.to_s
end
end
context 'value is blank' do
let(:value) { '' }
it 'is blank' do
expect(subject).to eql value
end
end
context 'value is nil' do
let(:value) { nil }
it 'is blank' do
expect(subject).to eql ''
end
end
end
describe '#validate_type_of_value' do
subject { described_class.new(custom_value).validate_type_of_value }
subject { instance.validate_type_of_value }
context 'value is included' do
let(:value) { custom_field.custom_options.first.id.to_s }

@ -29,13 +29,14 @@
require 'spec_helper'
describe CustomValue::StringStrategy do
let(:custom_value) {
let(:instance) { described_class.new(custom_value) }
let(:custom_value) do
double('CustomValue',
value: value)
}
end
describe '#typed_value' do
subject { described_class.new(custom_value).typed_value }
subject { instance.typed_value }
context 'value is some string' do
let(:value) { 'foo bar!' }
@ -53,8 +54,36 @@ describe CustomValue::StringStrategy do
end
end
describe '#formatted_value' do
subject { instance.formatted_value }
context 'value is some string' do
let(:value) { 'foo bar!' }
it 'is the string' do
is_expected.to eql value
end
end
context 'value is blank' do
let(:value) { '' }
it 'is a blank string' do
is_expected.to eql value
end
end
context 'value is nil' do
let(:value) { nil }
it 'is a blank string' do
is_expected.to eql ''
end
end
end
describe '#validate_type_of_value' do
subject { described_class.new(custom_value).validate_type_of_value }
subject { instance.validate_type_of_value }
context 'value is some string' do
let(:value) { 'foo bar!' }

@ -29,6 +29,7 @@
require 'spec_helper'
describe CustomValue::UserStrategy do
let(:instance) { described_class.new(custom_value) }
let(:custom_value) do
double('CustomValue',
value: value,
@ -40,7 +41,7 @@ describe CustomValue::UserStrategy do
let(:user) { FactoryGirl.build_stubbed(:user) }
describe '#parse_value/#typed_value' do
subject { described_class.new(custom_value) }
subject { instance }
context 'with a user' do
let(:value) { user }
@ -97,8 +98,54 @@ describe CustomValue::UserStrategy do
end
end
describe '#formatted_value' do
subject { instance.formatted_value }
context 'with a User' do
let(:value) { user }
it 'is the user to_s (without db access)' do
instance.parse_value(value)
expect(User)
.to_not receive(:find_by)
expect(subject).to eql value.to_s
end
end
context 'with an id string' do
let(:value) { user.id.to_s }
it 'is the user to_s (with db access)' do
allow(User)
.to receive(:find_by)
.with(id: user.id.to_s)
.and_return(user)
expect(subject).to eql user.to_s
end
end
context 'value is blank' do
let(:value) { '' }
it 'is blank and does not look for the user' do
expect(subject).to eql ''
end
end
context 'value is nil' do
let(:value) { nil }
it 'is blank and does not look for the user' do
expect(subject).to eql ''
end
end
end
describe '#validate_type_of_value' do
subject { described_class.new(custom_value).validate_type_of_value }
subject { instance.validate_type_of_value }
let(:allowed_ids) { %w(12 13) }
before do

@ -29,18 +29,19 @@
require 'spec_helper'
describe CustomValue::VersionStrategy do
let(:custom_value) {
let(:instance) { described_class.new(custom_value) }
let(:custom_value) do
double('CustomValue',
value: value,
custom_field: custom_field,
customized: customized)
}
end
let(:customized) { double('customized') }
let(:custom_field) { FactoryGirl.build(:custom_field) }
let(:version) { FactoryGirl.build_stubbed(:version) }
describe '#parse_value/#typed_value' do
subject { described_class.new(custom_value) }
subject { instance }
context 'with a version' do
let(:value) { version }
@ -97,8 +98,60 @@ describe CustomValue::VersionStrategy do
end
end
describe '#formatted_value' do
subject { instance.formatted_value }
context 'with a version' do
let(:value) { version }
it 'is the version to_s (without db access)' do
expect(Version)
.to_not receive(:find_by)
instance.parse_value(value)
is_expected.to eql value.to_s
end
end
context 'with an id string' do
let(:value) { version.id.to_s }
it 'is the version to_s (with db access)' do
allow(Version)
.to receive(:find_by)
.with(id: version.id.to_s)
.and_return(version)
is_expected.to eql version.to_s
end
end
context 'value is blank' do
let(:value) { '' }
it 'is blank and does not look for the version' do
expect(Version)
.to_not receive(:find_by)
is_expected.to eql ''
end
end
context 'value is nil' do
let(:value) { nil }
it 'is blank and does not look for the version' do
expect(Version)
.to_not receive(:find_by)
is_expected.to eql ''
end
end
end
describe '#validate_type_of_value' do
subject { described_class.new(custom_value).validate_type_of_value }
subject { instance.validate_type_of_value }
let(:allowed_ids) { %w(12 13) }
before do

@ -28,7 +28,7 @@
#++
require 'legacy_spec_helper'
describe 'CustomFieldFormat' do # TODO: what is this?
describe 'UserCustomField' do
before do
@project = FactoryGirl.create :valid_project
role = FactoryGirl.create :role, permissions: [:view_work_packages, :edit_work_packages]

Loading…
Cancel
Save