Fix syntax (w/Rubocop) in lib code

Signed-off-by: Alex Coles <alex@alexbcoles.com>
pull/3194/head
Alex Coles 9 years ago
parent ea713284a8
commit a6212fb304
  1. 4
      lib/api/root.rb
  2. 4
      lib/api/utilities/grape_helper.rb
  3. 4
      lib/api/v3/activities/activities_api.rb
  4. 1
      lib/api/v3/attachments/attachment_representer.rb
  5. 2
      lib/api/v3/attachments/attachments_api.rb
  6. 1
      lib/api/v3/priorities/priority_representer.rb
  7. 1
      lib/api/v3/projects/project_representer.rb
  8. 4
      lib/api/v3/queries/queries_api.rb
  9. 1
      lib/api/v3/statuses/status_representer.rb
  10. 1
      lib/api/v3/string_objects/string_objects_api.rb
  11. 3
      lib/api/v3/users/users_api.rb
  12. 8
      lib/api/v3/utilities/custom_field_injector.rb
  13. 1
      lib/api/v3/versions/version_representer.rb
  14. 2
      lib/api/v3/versions/versions_api.rb
  15. 1
      lib/api/v3/watchers/watcher_representer.rb
  16. 4
      lib/api/v3/work_packages/watchers_api.rb
  17. 4
      lib/api/v3/work_packages/work_package_representer.rb
  18. 6
      lib/copy_model.rb
  19. 5
      lib/custom_field_form_builder.rb
  20. 18
      lib/diff.rb
  21. 8
      lib/open_project/authentication/manager.rb
  22. 2
      lib/open_project/authentication/strategies/warden/global_basic_auth.rb
  23. 3
      lib/open_project/concerns/preview.rb
  24. 4
      lib/open_project/configuration/helpers.rb
  25. 19
      lib/open_project/nested_set/rebuild_patch.rb
  26. 7
      lib/open_project/nested_set/root_id_rebuilding.rb
  27. 3
      lib/open_project/object_linking.rb
  28. 4
      lib/open_project/omni_auth/authorization.rb
  29. 4
      lib/open_project/passwords.rb
  30. 2
      lib/open_project/principal_allowance_evaluator/base.rb
  31. 4
      lib/open_project/static_routing.rb
  32. 51
      lib/open_project/text_formatting.rb
  33. 2
      lib/open_project/themes/theme.rb
  34. 2
      lib/open_project/version.rb
  35. 1
      lib/open_project/wiki_formatting/macros/default.rb
  36. 5
      lib/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb
  37. 8
      lib/plugins/acts_as_customizable/lib/acts_as_customizable.rb
  38. 3
      lib/plugins/acts_as_journalized/lib/acts/journalized/journal_object_cache.rb
  39. 11
      lib/plugins/acts_as_journalized/lib/redmine/acts/journalized/changes.rb
  40. 1
      lib/plugins/acts_as_journalized/lib/redmine/acts/journalized/creation.rb
  41. 2
      lib/plugins/acts_as_journalized/lib/redmine/acts/journalized/format_hooks.rb
  42. 2
      lib/plugins/acts_as_journalized/lib/redmine/acts/journalized/save_hooks.rb
  43. 3
      lib/plugins/acts_as_journalized/lib/redmine/acts/journalized/versions.rb
  44. 15
      lib/plugins/acts_as_journalized/test/reset_test.rb
  45. 7
      lib/plugins/acts_as_journalized/test/reversion_test.rb
  46. 6
      lib/plugins/acts_as_journalized/test/version_test.rb
  47. 3
      lib/plugins/acts_as_journalized/test/versions_test.rb
  48. 3
      lib/plugins/acts_as_tree/lib/active_record/acts/tree.rb
  49. 2
      lib/plugins/acts_as_watchable/lib/acts_as_watchable.rb
  50. 10
      lib/redmine/activity/fetcher.rb
  51. 2
      lib/redmine/core_ext/string/conversions.rb
  52. 12
      lib/redmine/default_data/loader.rb
  53. 4
      lib/redmine/i18n.rb
  54. 62
      lib/redmine/menu_manager/menu_helper.rb
  55. 4
      lib/redmine/menu_manager/top_menu_helper.rb
  56. 6
      lib/redmine/mime_type.rb
  57. 2
      lib/redmine/plugin.rb
  58. 10
      lib/redmine/scm/adapters/git_adapter.rb
  59. 2
      lib/redmine/scm/adapters/subversion_adapter.rb
  60. 3
      lib/redmine/unified_diff.rb
  61. 11
      lib/redmine/views/my_page/block.rb
  62. 4
      lib/redmine/wiki_formatting.rb
  63. 6
      lib/redmine/wiki_formatting/textile/formatter.rb
  64. 8
      lib/tabular_form_builder.rb

@ -130,7 +130,7 @@ module API
raise ArgumentError if projects.nil? && !global raise ArgumentError if projects.nil? && !global
projects = Array(projects) projects = Array(projects)
authorized = permissions.any? do |permission| authorized = permissions.any? { |permission|
allowed_condition = Project.allowed_to_condition(user, permission) allowed_condition = Project.allowed_to_condition(user, permission)
allowed_projects = Project.where(allowed_condition) allowed_projects = Project.where(allowed_condition)
@ -139,7 +139,7 @@ module API
else else
!(allowed_projects & projects).empty? !(allowed_projects & projects).empty?
end end
end }
raise API::Errors::Unauthorized unless authorized raise API::Errors::Unauthorized unless authorized
authorized authorized

@ -49,12 +49,12 @@ module API
end end
def error_response(rescued_error, error = nil, rescue_subclasses: nil, headers: {}) def error_response(rescued_error, error = nil, rescue_subclasses: nil, headers: {})
default_response = lambda do |e| default_response = lambda { |e|
representer = ::API::V3::Errors::ErrorRepresenter.new e representer = ::API::V3::Errors::ErrorRepresenter.new e
env['api.format'] = 'hal+json' env['api.format'] = 'hal+json'
error_response status: e.code, message: representer.to_json, headers: headers error_response status: e.code, message: representer.to_json, headers: headers
end }
response = response =
if error.nil? if error.nil?

@ -33,12 +33,10 @@ module API
module Activities module Activities
class ActivitiesAPI < ::API::OpenProjectAPI class ActivitiesAPI < ::API::OpenProjectAPI
resources :activities do resources :activities do
params do params do
requires :id, desc: 'Activity id' requires :id, desc: 'Activity id'
end end
route_param :id do route_param :id do
before do before do
@activity = Journal.find(params[:id]) @activity = Journal.find(params[:id])
@representer = ActivityRepresenter.new(@activity, current_user: current_user) @representer = ActivityRepresenter.new(@activity, current_user: current_user)
@ -77,9 +75,7 @@ module API
save_activity(@activity) save_activity(@activity)
end end
end end
end end
end end
end end

@ -34,7 +34,6 @@ module API
module V3 module V3
module Attachments module Attachments
class AttachmentRepresenter < ::API::Decorators::Single class AttachmentRepresenter < ::API::Decorators::Single
self_link title_getter: -> (*) { represented.filename } self_link title_getter: -> (*) { represented.filename }
linked_property :author, linked_property :author,

@ -33,12 +33,10 @@ module API
module Attachments module Attachments
class AttachmentsAPI < ::API::OpenProjectAPI class AttachmentsAPI < ::API::OpenProjectAPI
resources :attachments do resources :attachments do
params do params do
requires :id, desc: 'Attachment id' requires :id, desc: 'Attachment id'
end end
route_param :id do route_param :id do
before do before do
@attachment = Attachment.find(params[:id]) @attachment = Attachment.find(params[:id])

@ -34,7 +34,6 @@ module API
module V3 module V3
module Priorities module Priorities
class PriorityRepresenter < ::API::Decorators::Single class PriorityRepresenter < ::API::Decorators::Single
self_link self_link
property :id, render_nil: true property :id, render_nil: true

@ -34,7 +34,6 @@ module API
module V3 module V3
module Projects module Projects
class ProjectRepresenter < ::API::Decorators::Single class ProjectRepresenter < ::API::Decorators::Single
self_link self_link
link :createWorkPackage do link :createWorkPackage do

@ -58,10 +58,10 @@ module API
# Normalizing the query name can result in conflicts and empty names in case all # Normalizing the query name can result in conflicts and empty names in case all
# characters are filtered out. A random name doesn't have these problems. # characters are filtered out. A random name doesn't have these problems.
query_menu_item = MenuItems::QueryMenuItem.find_or_initialize_by( query_menu_item = MenuItems::QueryMenuItem.find_or_initialize_by(
navigatable_id: @query.id) do |item| navigatable_id: @query.id) { |item|
item.name = SecureRandom.uuid item.name = SecureRandom.uuid
item.title = @query.name item.title = @query.name
end }
query_menu_item.save! query_menu_item.save!
@representer @representer
end end

@ -31,7 +31,6 @@ module API
module V3 module V3
module Statuses module Statuses
class StatusRepresenter < ::API::Decorators::Single class StatusRepresenter < ::API::Decorators::Single
self_link self_link
property :id, render_nil: true property :id, render_nil: true

@ -34,7 +34,6 @@ module API
module StringObjects module StringObjects
class StringObjectsAPI < ::API::OpenProjectAPI class StringObjectsAPI < ::API::OpenProjectAPI
resources :string_objects do resources :string_objects do
params do params do
requires :value, type: String requires :value, type: String
end end

@ -47,12 +47,10 @@ module API
end end
resources :users do resources :users do
params do params do
requires :id, desc: 'User\'s id' requires :id, desc: 'User\'s id'
end end
route_param :id do route_param :id do
before do before do
@user = User.find(params[:id]) @user = User.find(params[:id])
end end
@ -70,7 +68,6 @@ module API
end end
namespace :lock do namespace :lock do
# Authenticate lock transitions # Authenticate lock transitions
before do before do
unless current_user.admin? unless current_user.admin?

@ -83,9 +83,9 @@ module API
end end
def create_value_representer_for_property_patching(customizable, representer) def create_value_representer_for_property_patching(customizable, representer)
property_fields = customizable.available_custom_fields.select do |cf| property_fields = customizable.available_custom_fields.select { |cf|
property_field?(cf) property_field?(cf)
end }
injector = CustomFieldInjector.new(representer) injector = CustomFieldInjector.new(representer)
property_fields.each do |custom_field| property_fields.each do |custom_field|
@ -96,9 +96,9 @@ module API
end end
def create_value_representer_for_link_patching(customizable, representer) def create_value_representer_for_link_patching(customizable, representer)
linked_fields = customizable.available_custom_fields.select do |cf| linked_fields = customizable.available_custom_fields.select { |cf|
linked_field?(cf) linked_field?(cf)
end }
injector = CustomFieldInjector.new(representer) injector = CustomFieldInjector.new(representer)
linked_fields.each do |custom_field| linked_fields.each do |custom_field|

@ -34,7 +34,6 @@ module API
module V3 module V3
module Versions module Versions
class VersionRepresenter < ::API::Decorators::Single class VersionRepresenter < ::API::Decorators::Single
self_link self_link
linked_property :definingProject, linked_property :definingProject,

@ -32,9 +32,7 @@ module API
module Versions module Versions
class VersionsAPI < ::API::OpenProjectAPI class VersionsAPI < ::API::OpenProjectAPI
resources :versions do resources :versions do
route_param :id do route_param :id do
before do before do
@version = Version.find(params[:id]) @version = Version.find(params[:id])

@ -34,7 +34,6 @@ module API
module V3 module V3
module Watchers module Watchers
class WatcherRepresenter < ::API::Decorators::Single class WatcherRepresenter < ::API::Decorators::Single
property :user, property :user,
exec_context: :decorator, exec_context: :decorator,
getter: -> (*) { getter: -> (*) {

@ -81,9 +81,9 @@ module API
Services::CreateWatcher.new(@work_package, user).run( Services::CreateWatcher.new(@work_package, user).run(
success: -> (result) { status(200) unless result[:created] }, success: -> (result) { status(200) unless result[:created] },
failure: -> (watcher) { failure: -> (watcher) {
messages = watcher.errors.map do |attribute, message| messages = watcher.errors.map { |attribute, message|
watcher.errors.full_message(attribute, message) + '.' watcher.errors.full_message(attribute, message) + '.'
end }
raise ::API::Errors::Validation.new(messages) raise ::API::Errors::Validation.new(messages)
} }
) )

@ -333,9 +333,9 @@ module API
def relations def relations
relations = represented.relations relations = represented.relations
visible_relations = relations.select do |relation| visible_relations = relations.select { |relation|
relation.other_work_package(represented).visible? relation.other_work_package(represented).visible?
end }
visible_relations.map do |relation| visible_relations.map do |relation|
Relations::RelationRepresenter.new(relation, Relations::RelationRepresenter.new(relation,

@ -59,9 +59,9 @@ module CopyModel
to_be_copied = self.class.reflect_on_all_associations.map(&:name) to_be_copied = self.class.reflect_on_all_associations.map(&:name)
to_be_copied = Array(options[:only]) unless options[:only].nil? to_be_copied = Array(options[:only]) unless options[:only].nil?
to_be_copied = to_be_copied.map(&:to_s).sort do |a, b| to_be_copied = to_be_copied.map(&:to_s).sort { |a, b|
(copy_precedence.map(&:to_s).index(a) || -1) <=> (copy_precedence.map(&:to_s).index(b) || -1) (copy_precedence.map(&:to_s).index(a) || -1) <=> (copy_precedence.map(&:to_s).index(b) || -1)
end.map(&:to_sym) }.map(&:to_sym)
with_model(from_model) do |model| with_model(from_model) do |model|
self.class.transaction do self.class.transaction do
@ -102,8 +102,6 @@ module CopyModel
else else
return model return model
end end
else
nil
end end
end end

@ -30,7 +30,6 @@
require 'action_view/helpers/form_helper' require 'action_view/helpers/form_helper'
class CustomFieldFormBuilder < TabularFormBuilder class CustomFieldFormBuilder < TabularFormBuilder
# Return custom field html tag corresponding to its format # Return custom field html tag corresponding to its format
def custom_field(options = {}) def custom_field(options = {})
input = custom_field_input(options) input = custom_field_input(options)
@ -90,11 +89,11 @@ class CustomFieldFormBuilder < TabularFormBuilder
end end
def custom_field_field_name def custom_field_field_name
"#{object_name}[#{ object.custom_field.id }]" "#{object_name}[#{object.custom_field.id}]"
end end
def custom_field_field_id def custom_field_field_id
"#{object_name}#{ object.custom_field.id }".gsub(/[\[\]]+/, '_') "#{object_name}#{object.custom_field.id}".gsub(/[\[\]]+/, '_')
end end
# Return custom field label tag # Return custom field label tag

@ -56,11 +56,11 @@ module RedmineDiff
thresh = [] thresh = []
links = [] links = []
(astart..afinish).each { |aindex| (astart..afinish).each do |aindex|
aelem = a[aindex] aelem = a[aindex]
next unless bmatches.has_key? aelem next unless bmatches.has_key? aelem
k = nil k = nil
bmatches[aelem].reverse.each { |bindex| bmatches[aelem].reverse_each { |bindex|
if k && (thresh[k] > bindex) && (thresh[k - 1] < bindex) if k && (thresh[k] > bindex) && (thresh[k - 1] < bindex)
thresh[k] = bindex thresh[k] = bindex
else else
@ -68,7 +68,7 @@ module RedmineDiff
end end
links[k] = [(k == 0) ? nil : links[k - 1], aindex, bindex] if k links[k] = [(k == 0) ? nil : links[k - 1], aindex, bindex] if k
} }
} end
if !thresh.empty? if !thresh.empty?
link = links[thresh.length - 1] link = links[thresh.length - 1]
@ -112,7 +112,7 @@ module RedmineDiff
def compactdiffs def compactdiffs
diffs = [] diffs = []
@diffs.each { |df| @diffs.each do |df|
i = 0 i = 0
curdiff = [] curdiff = []
while i < df.length while i < df.length
@ -129,7 +129,7 @@ module RedmineDiff
curdiff.push [whot, p, s] curdiff.push [whot, p, s]
end end
diffs.push curdiff diffs.push curdiff
} end
diffs diffs
end end
@ -184,14 +184,14 @@ module Diffable
def reverse_hash(range = (0...length)) def reverse_hash(range = (0...length))
revmap = {} revmap = {}
range.each { |i| range.each do |i|
elem = self[i] elem = self[i]
if revmap.has_key? elem if revmap.has_key? elem
revmap[elem].push i revmap[elem].push i
else else
revmap[elem] = [i] revmap[elem] = [i]
end end
} end
revmap revmap
end end
@ -231,7 +231,7 @@ module Diffable
end end
ai = 0 ai = 0
bi = 0 bi = 0
diff.diffs.each { |d| diff.diffs.each do |d|
d.each { |mod| d.each { |mod|
case mod[0] case mod[0]
when '-' when '-'
@ -253,7 +253,7 @@ module Diffable
raise 'Unknown diff action' raise 'Unknown diff action'
end end
} }
} end
while ai < length while ai < length
newary << self[ai] newary << self[ai]
ai += 1 ai += 1

@ -1,20 +1,18 @@
module OpenProject module OpenProject
module Authentication module Authentication
class Manager < Warden::Manager class Manager < Warden::Manager
serialize_into_session do |user| serialize_into_session(&:id)
user.id
end
serialize_from_session do |id| serialize_from_session do |id|
User.find id User.find id
end end
def initialize(app, options = {}, &configure) def initialize(app, options = {}, &configure)
block = lambda do |config| block = lambda { |config|
self.class.configure config self.class.configure config
configure.call config if configure configure.call config if configure
end }
super app, options, &block super app, options, &block
end end

@ -40,7 +40,7 @@ module OpenProject
end end
if config[:password].blank? if config[:password].blank?
raise ArgumentError, "password must not be empty" raise ArgumentError, 'password must not be empty'
end end
@configuration = config @configuration = config

@ -72,8 +72,7 @@ module OpenProject::Concerns::Preview
klass ||= param_name.to_s.classify.constantize klass ||= param_name.to_s.classify.constantize
texts = Array(attributes).each_with_object({}) do |attribute, list| texts = Array(attributes).each_with_object({}) do |attribute, list|
caption = (attribute == :notes) ? Journal.human_attribute_name(:notes) caption = (attribute == :notes) ? Journal.human_attribute_name(:notes) : klass.human_attribute_name(attribute)
: klass.human_attribute_name(attribute)
text = params[param_name][attribute] text = params[param_name][attribute]
list[caption] = text list[caption] = text
end end

@ -71,9 +71,9 @@ module OpenProject
end end
def hidden_menu_items def hidden_menu_items
menus = self['hidden_menu_items'].map do |label, nodes| menus = self['hidden_menu_items'].map { |label, nodes|
[label, array(nodes)] [label, array(nodes)]
end }
Hash[menus] Hash[menus]
end end

@ -56,9 +56,9 @@ module OpenProject::NestedSet::RebuildPatch
"#{quoted_table_name}.#{quoted_right_column_name} >= parent.#{quoted_right_column_name}))" "#{quoted_table_name}.#{quoted_right_column_name} >= parent.#{quoted_right_column_name}))"
scope :invalid_duplicates_in_columns, lambda { scope :invalid_duplicates_in_columns, lambda {
scope_string = Array(acts_as_nested_set_options[:scope]).map do |c| scope_string = Array(acts_as_nested_set_options[:scope]).map { |c|
"#{quoted_table_name}.#{connection.quote_column_name(c)} = duplicates.#{connection.quote_column_name(c)}" "#{quoted_table_name}.#{connection.quote_column_name(c)} = duplicates.#{connection.quote_column_name(c)}"
end.join(' AND ') }.join(' AND ')
scope_string = scope_string.size > 0 ? scope_string + ' AND ' : '' scope_string = scope_string.size > 0 ? scope_string + ' AND ' : ''
@ -71,9 +71,9 @@ module OpenProject::NestedSet::RebuildPatch
} }
scope :invalid_roots, lambda { scope :invalid_roots, lambda {
scope_string = Array(acts_as_nested_set_options[:scope]).map do |c| scope_string = Array(acts_as_nested_set_options[:scope]).map { |c|
"#{quoted_table_name}.#{connection.quote_column_name(c)} = other.#{connection.quote_column_name(c)}" "#{quoted_table_name}.#{connection.quote_column_name(c)} = other.#{connection.quote_column_name(c)}"
end.join(' AND ') }.join(' AND ')
scope_string = scope_string.size > 0 ? scope_string + ' AND ' : '' scope_string = scope_string.size > 0 ? scope_string + ' AND ' : ''
@ -132,8 +132,7 @@ module OpenProject::NestedSet::RebuildPatch
h[k] = 0 h[k] = 0
end end
set_left_and_rights = lambda do |node| set_left_and_rights = lambda { |node|
# set left # set left
node[left_column_name] = indices[scope.call(node)] += 1 node[left_column_name] = indices[scope.call(node)] += 1
# find # find
@ -142,18 +141,18 @@ module OpenProject::NestedSet::RebuildPatch
quoted_right_column_name, quoted_right_column_name,
acts_as_nested_set_options[:order]].compact.join(', ')) acts_as_nested_set_options[:order]].compact.join(', '))
children.each { |n| set_left_and_rights.call(n) } children.each do |n| set_left_and_rights.call(n) end
# set right # set right
node[right_column_name] = indices[scope.call(node)] += 1 node[right_column_name] = indices[scope.call(node)] += 1
changes = node.changes.inject({}) do |hash, (attribute, _values)| changes = node.changes.inject({}) { |hash, (attribute, _values)|
hash[attribute] = node.send(attribute.to_s) hash[attribute] = node.send(attribute.to_s)
hash hash
end }
update_all(changes, id: node.id) unless changes.empty? update_all(changes, id: node.id) unless changes.empty?
end }
# Find root node(s) # Find root node(s)
# or take provided # or take provided

@ -36,7 +36,6 @@ module OpenProject::NestedSet
module RootIdRebuilding module RootIdRebuilding
def self.included(base) def self.included(base)
base.class_eval do base.class_eval do
include RebuildPatch include RebuildPatch
# find all nodes # find all nodes
@ -86,7 +85,7 @@ module OpenProject::NestedSet
hash[ancestor_id] = find_by(id: ancestor_id) hash[ancestor_id] = find_by(id: ancestor_id)
end end
fix_known_invalid_root_ids = lambda do fix_known_invalid_root_ids = lambda {
invalid_nodes = invalid_root_ids invalid_nodes = invalid_root_ids
invalid_roots = [] invalid_roots = []
@ -104,12 +103,12 @@ module OpenProject::NestedSet
if invalid_root_ids_to_fix.empty? || invalid_root_ids_to_fix.map(&:id).include?(ancestor.id) if invalid_root_ids_to_fix.empty? || invalid_root_ids_to_fix.map(&:id).include?(ancestor.id)
update_all({ root_id: ancestor.id }, update_all({ root_id: ancestor.id },
{ id: node.id }) id: node.id)
end end
end end
fix_known_invalid_root_ids.call unless (invalid_roots.map(&:id) & invalid_root_ids_to_fix.map(&:id)).empty? fix_known_invalid_root_ids.call unless (invalid_roots.map(&:id) & invalid_root_ids_to_fix.map(&:id)).empty?
end }
fix_known_invalid_root_ids.call fix_known_invalid_root_ids.call

@ -45,8 +45,7 @@ module OpenProject
def link_to_work_package_preview(context = nil, options = {}) def link_to_work_package_preview(context = nil, options = {})
form_id = options[:form_id] || 'work_package-form-preview' form_id = options[:form_id] || 'work_package-form-preview'
path = (context.is_a? WorkPackage) ? preview_work_package_path(context) path = (context.is_a? WorkPackage) ? preview_work_package_path(context) : preview_work_packages_path
: preview_work_packages_path
preview_link path, "#{form_id}-preview" preview_link path, "#{form_id}-preview"
end end

@ -35,7 +35,7 @@ module OpenProject
# Checks whether the given user is authorized to login by calling # Checks whether the given user is authorized to login by calling
# all registered callbacks. If all callbacks approve the user is authorized and may log in. # all registered callbacks. If all callbacks approve the user is authorized and may log in.
def self.authorized?(auth_hash) def self.authorized?(auth_hash)
rejection = callbacks.find_map do |callback| rejection = callbacks.find_map { |callback|
d = callback.authorize auth_hash d = callback.authorize auth_hash
if d.is_a? Decision if d.is_a? Decision
@ -43,7 +43,7 @@ module OpenProject
else else
fail ArgumentError, 'Expecting Callback#authorize to return a Decision.' fail ArgumentError, 'Expecting Callback#authorize to return a Decision.'
end end
end }
rejection || Approval.new rejection || Approval.new
end end

@ -104,10 +104,10 @@ module OpenProject
def self.rules_description def self.rules_description
return '' if min_adhered_rules == 0 return '' if min_adhered_rules == 0
rules = active_rules.map do |rule| rules = active_rules.map { |rule|
I18n.t(rule.to_sym, I18n.t(rule.to_sym,
scope: [:activerecord, :errors, :models, :user, :attributes, :password]) scope: [:activerecord, :errors, :models, :user, :attributes, :password])
end }
I18n.t(:weak, I18n.t(:weak,
scope: [:activerecord, :errors, :models, :user, :attributes, :password], scope: [:activerecord, :errors, :models, :user, :attributes, :password],

@ -55,7 +55,7 @@ class OpenProject::PrincipalAllowanceEvaluator::Base
[] []
end end
def self.eager_load_for_project_authorization(project) def self.eager_load_for_project_authorization(_project)
nil nil
end end
end end

@ -43,11 +43,11 @@ module OpenProject
def default_url_options def default_url_options
options = ActionMailer::Base.default_url_options.clone options = ActionMailer::Base.default_url_options.clone
reverse_merge = lambda do |opt, value| reverse_merge = lambda { |opt, value|
unless options[opt] || value.blank? unless options[opt] || value.blank?
options[opt] = value options[opt] = value
end end
end }
reverse_merge.call :script_name, OpenProject::Configuration.rails_relative_url_root reverse_merge.call :script_name, OpenProject::Configuration.rails_relative_url_root
reverse_merge.call :host, OpenProject::StaticRouting::UrlHelpers.host reverse_merge.call :host, OpenProject::StaticRouting::UrlHelpers.host

@ -88,17 +88,17 @@ module OpenProject
text = Redmine::WikiFormatting.to_html(format, text, text = Redmine::WikiFormatting.to_html(format, text,
object: obj, object: obj,
attribute: attr, attribute: attr,
edit: edit) do |macro, macro_args| edit: edit) { |macro, macro_args|
exec_macro(macro, obj, macro_args, view: self, edit: edit, project: project) exec_macro(macro, obj, macro_args, view: self, edit: edit, project: project)
end }
# TODO: transform modifications into WikiFormatting Helper, or at least ask the helper if he wants his stuff to be modified # TODO: transform modifications into WikiFormatting Helper, or at least ask the helper if he wants his stuff to be modified
@parsed_headings = [] @parsed_headings = []
text = parse_non_pre_blocks(text) do |text| text = parse_non_pre_blocks(text) { |text|
[:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings, :parse_relative_urls].each do |method_name| [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings, :parse_relative_urls].each do |method_name|
send method_name, text, project, obj, attr, only_path, options send method_name, text, project, obj, attr, only_path, options
end end
end }
if @parsed_headings.any? if @parsed_headings.any?
replace_toc(text, @parsed_headings) replace_toc(text, @parsed_headings)
@ -115,7 +115,10 @@ module OpenProject
parsed = '' parsed = ''
while !s.eos? while !s.eos?
s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im) s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im)
text, full_tag, closing, tag = s[1], s[2], s[3], s[4] text = s[1]
full_tag = s[2]
closing = s[3]
tag = s[4]
if tags.empty? if tags.empty?
yield text yield text
end end
@ -156,16 +159,19 @@ module OpenProject
def parse_relative_urls(text, _project, _obj, _attr, only_path, _options) def parse_relative_urls(text, _project, _obj, _attr, only_path, _options)
return if only_path return if only_path
text.gsub!(RELATIVE_LINK_RE) do |m| text.gsub!(RELATIVE_LINK_RE) do |m|
href, relative_url = $1, $2 || $3 href = $1
relative_url = $2 || $3
next m unless href.present? next m unless href.present?
if defined?(request) && request.present? if defined?(request) && request.present?
# we have a request! # we have a request!
protocol, host_with_port = request.protocol, request.host_with_port protocol = request.protocol
host_with_port = request.host_with_port
elsif @controller elsif @controller
# use the same methods as url_for in the Mailer # use the same methods as url_for in the Mailer
url_opts = @controller.class.default_url_options url_opts = @controller.class.default_url_options
next m unless url_opts && url_opts[:protocol] && url_opts[:host] next m unless url_opts && url_opts[:protocol] && url_opts[:host]
protocol, host_with_port = "#{url_opts[:protocol]}://", url_opts[:host] protocol = "#{url_opts[:protocol]}://"
host_with_port = url_opts[:host]
else else
next m next m
end end
@ -178,7 +184,10 @@ module OpenProject
if options[:attachments] || (obj && obj.respond_to?(:attachments)) if options[:attachments] || (obj && obj.respond_to?(:attachments))
attachments = nil attachments = nil
text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
filename, ext, alt, alttext = $1.downcase, $2, $3, $4 filename = $1.downcase
ext = $2
alt = $3
alttext = $4
attachments ||= (options[:attachments] || obj.attachments).sort_by(&:created_on).reverse attachments ||= (options[:attachments] || obj.attachments).sort_by(&:created_on).reverse
# search for the picture in attachments # search for the picture in attachments
if found = attachments.detect { |att| att.filename.downcase == filename } if found = attachments.detect { |att| att.filename.downcase == filename }
@ -208,7 +217,10 @@ module OpenProject
def parse_wiki_links(text, project, _obj, _attr, only_path, options) def parse_wiki_links(text, project, _obj, _attr, only_path, options)
text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |_m| text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |_m|
link_project = project link_project = project
esc, all, page, title = $1, $2, $3, $5 esc = $1
all = $2
page = $3
title = $5
if esc.nil? if esc.nil?
if page =~ /\A([^\:]+)\:(.*)\z/ if page =~ /\A([^\:]+)\:(.*)\z/
link_project = Project.find_by(identifier: $1) || Project.find_by(name: $1) link_project = Project.find_by(identifier: $1) || Project.find_by(name: $1)
@ -220,7 +232,8 @@ module OpenProject
# extract anchor # extract anchor
anchor = nil anchor = nil
if page =~ /\A(.+?)\#(.+)\z/ if page =~ /\A(.+?)\#(.+)\z/
page, anchor = $1, $2 page = $1
anchor = $2
end end
# check if page exists # check if page exists
wiki_page = link_project.wiki.find_page(page) wiki_page = link_project.wiki.find_page(page)
@ -276,7 +289,13 @@ module OpenProject
# identifier:source:some/file # identifier:source:some/file
def parse_redmine_links(text, project, obj, attr, only_path, options) def parse_redmine_links(text, project, obj, attr, only_path, options)
text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|version|commit|source|export|message|project)?((#+|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |_m| text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|version|commit|source|export|message|project)?((#+|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |_m|
leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10 leading = $1
esc = $2
project_prefix = $3
project_identifier = $4
prefix = $5
sep = $7 || $9
identifier = $8 || $10
link = nil link = nil
if project_identifier if project_identifier
project = Project.visible.find_by(identifier: project_identifier) project = Project.visible.find_by(identifier: project_identifier)
@ -342,7 +361,9 @@ module OpenProject
when 'source', 'export' when 'source', 'export'
if project && project.repository && User.current.allowed_to?(:browse_repository, project) if project && project.repository && User.current.allowed_to?(:browse_repository, project)
name =~ %r{\A[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?\z} name =~ %r{\A[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?\z}
path, rev, anchor = $1, $3, $5 path = $1
rev = $3
anchor = $5
link = link_to h("#{project_prefix}#{prefix}:#{name}"), { controller: '/repositories', action: 'entry', project_id: project, link = link_to h("#{project_prefix}#{prefix}:#{name}"), { controller: '/repositories', action: 'entry', project_id: project,
path: path.to_s, path: path.to_s,
rev: rev, rev: rev,
@ -375,7 +396,9 @@ module OpenProject
return if options[:headings] == false return if options[:headings] == false
text.gsub!(HEADING_RE) do text.gsub!(HEADING_RE) do
level, attrs, content = $1.to_i, $2, $3 level = $1.to_i
attrs = $2
content = $3
item = strip_tags(content).strip item = strip_tags(content).strip
anchor = item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') anchor = item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
@parsed_headings << [level, anchor, item] @parsed_headings << [level, anchor, item]

@ -101,7 +101,7 @@ module OpenProject
def overridden_images def overridden_images
@overridden_images ||= \ @overridden_images ||= \
begin begin
Dir.chdir(overridden_images_path) { Dir.glob('**/*') } Dir.chdir(overridden_images_path) do Dir.glob('**/*') end
rescue Errno::ENOENT # overridden_images_path missing rescue Errno::ENOENT # overridden_images_path missing
[] []
end.to_set end.to_set

@ -55,8 +55,6 @@ module OpenProject
revision = `git rev-parse HEAD` revision = `git rev-parse HEAD`
if revision.present? if revision.present?
revision.strip[0..8] revision.strip[0..8]
else
nil
end end
end end

@ -74,7 +74,6 @@ module OpenProject
pages = ([page] + page.descendants).group_by(&:parent_id) pages = ([page] + page.descendants).group_by(&:parent_id)
render_page_hierarchy(pages, options[:parent] ? page.parent_id : page.id) render_page_hierarchy(pages, options[:parent] ? page.parent_id : page.id)
end end
end end
Redmine::WikiFormatting::Macros.register do Redmine::WikiFormatting::Macros.register do

@ -97,7 +97,7 @@ module Redmine
end end
result.flatten! result.flatten!
result.each { |e| e.event_type = event_type.dup.singularize unless e.event_type } result.each do |e| e.event_type = event_type.dup.singularize unless e.event_type end
result result
end end
@ -210,8 +210,7 @@ module Redmine
def fill_events(provider, activity, events) def fill_events(provider, activity, events)
events.each_with_object([]) do |e, result| events.each_with_object([]) do |e, result|
datetime = e['event_datetime'].is_a?(String) ? DateTime.parse(e['event_datetime']) datetime = e['event_datetime'].is_a?(String) ? DateTime.parse(e['event_datetime']) : e['event_datetime']
: e['event_datetime']
event = Redmine::Acts::ActivityProvider::Event.new(self, event = Redmine::Acts::ActivityProvider::Event.new(self,
nil, nil,
nil, nil,

@ -66,13 +66,13 @@ module Redmine
# Sets the values of the object's custom fields # Sets the values of the object's custom fields
# values is an array like [{'id' => 1, 'value' => 'foo'}, {'id' => 2, 'value' => 'bar'}] # values is an array like [{'id' => 1, 'value' => 'foo'}, {'id' => 2, 'value' => 'bar'}]
def custom_fields=(values) def custom_fields=(values)
values_to_hash = values.inject({}) do |hash, v| values_to_hash = values.inject({}) { |hash, v|
v = v.stringify_keys v = v.stringify_keys
if v['id'] && v.has_key?('value') if v['id'] && v.has_key?('value')
hash[v['id']] = v['value'] hash[v['id']] = v['value']
end end
hash hash
end }
self.custom_field_values = values_to_hash self.custom_field_values = values_to_hash
end end
@ -89,12 +89,12 @@ module Redmine
end end
def custom_field_values def custom_field_values
@custom_field_values ||= available_custom_fields.map do |custom_field| @custom_field_values ||= available_custom_fields.map { |custom_field|
existing_cv = custom_values.detect { |v| v.custom_field == custom_field } existing_cv = custom_values.detect { |v| v.custom_field == custom_field }
existing_cv || custom_values.build(customized: self, existing_cv || custom_values.build(customized: self,
custom_field: custom_field, custom_field: custom_field,
value: nil) value: nil)
end }
end end
def visible_custom_field_values def visible_custom_field_values

@ -31,8 +31,7 @@ module Acts
class JournalObjectCache class JournalObjectCache
# unloadable # unloadable
def fetch(klass, id, &block) def fetch(klass, id, &_block)
@cache ||= Hash.new do |klass_hash, klass_key| @cache ||= Hash.new do |klass_hash, klass_key|
klass_hash[klass_key] = Hash.new do |id_hash, id_key| klass_hash[klass_key] = Hash.new do |id_hash, id_key|
id_hash[id_key] = yield klass_key, id_key id_hash[id_key] = yield klass_key, id_key

@ -86,7 +86,8 @@ module Redmine::Acts::Journalized
# version number, a symbol representing an association proxy method, a string representing a # version number, a symbol representing an association proxy method, a string representing a
# journal tag or a journal object itself. # journal tag or a journal object itself.
def changes_between(from, to) def changes_between(from, to)
from_number, to_number = journals.journal_at(from), journals.journal_at(to) from_number = journals.journal_at(from)
to_number = journals.journal_at(to)
return {} if from_number == to_number return {} if from_number == to_number
chain = journals.between(from_number, to_number).reject(&:initial?) chain = journals.between(from_number, to_number).reject(&:initial?)
return {} if chain.empty? return {} if chain.empty?
@ -118,11 +119,11 @@ module Redmine::Acts::Journalized
# creation. Incremental changes are reset when the record is saved because they represent # creation. Incremental changes are reset when the record is saved because they represent
# a subset of the dirty attribute changes, which are reset upon save. # a subset of the dirty attribute changes, which are reset upon save.
def incremental_journal_changes def incremental_journal_changes
changed.inject({}) do |h, attr| changed.inject({}) { |h, attr|
h[attr] = attribute_change(attr) unless !attribute_change(attr).nil? && h[attr] = attribute_change(attr) unless !attribute_change(attr).nil? &&
attribute_change(attr)[0].blank? && attribute_change(attr)[1].blank? attribute_change(attr)[0].blank? && attribute_change(attr)[1].blank?
h h
end.slice(*journaled_columns) }.slice(*journaled_columns)
end end
# Simply resets the cumulative changes after journal creation. # Simply resets the cumulative changes after journal creation.
@ -156,10 +157,10 @@ module Redmine::Acts::Journalized
# "age" => [25, 54] # "age" => [25, 54]
# } # }
def append_changes(changes) def append_changes(changes)
changes.inject(self) do |new_changes, (attribute, change)| changes.inject(self) { |new_changes, (attribute, change)|
new_change = [new_changes.fetch(attribute, change).first, change.last] new_change = [new_changes.fetch(attribute, change).first, change.last]
new_changes.merge(attribute => new_change) new_changes.merge(attribute => new_change)
end.reject do |_attribute, change| }.reject do |_attribute, change|
change.first == change.last change.first == change.last
end end
end end

@ -105,7 +105,6 @@ module Redmine::Acts::Journalized
initial_changes = {} initial_changes = {}
JournalManager.journal_class(self.class).journaled_attributes.each do |name| JournalManager.journal_class(self.class).journaled_attributes.each do |name|
# Set the current attributes as initial attributes # Set the current attributes as initial attributes
# This works as a fallback if no prior change is found # This works as a fallback if no prior change is found
initial_changes[name] = send(name) initial_changes[name] = send(name)

@ -71,7 +71,7 @@ module Redmine::Acts::Journalized
end end
end end
raise ArgumentError "Provide either a class or a block defining the value formatting" if klass.nil? raise ArgumentError 'Provide either a class or a block defining the value formatting' if klass.nil?
JournalFormatter.register formatter.to_sym => klass JournalFormatter.register formatter.to_sym => klass
end end

@ -82,7 +82,6 @@ module Redmine::Acts::Journalized
end end
def save_journal_with_retry(journal, tries: 2) def save_journal_with_retry(journal, tries: 2)
begin
journal.save! journal.save!
rescue ActiveRecord::RecordInvalid => e rescue ActiveRecord::RecordInvalid => e
# TODO: rescue from ActiveRecord::RecordNotUnique as well # TODO: rescue from ActiveRecord::RecordNotUnique as well
@ -94,7 +93,6 @@ module Redmine::Acts::Journalized
raise raise
end end
end end
end
module ClassMethods module ClassMethods
end end

@ -75,7 +75,8 @@ module Redmine::Acts::Journalized
# given by the arguments. If the +from+ value represents a journal before that of the +to+ # given by the arguments. If the +from+ value represents a journal before that of the +to+
# value, the array will be ordered from earliest to latest. The reverse is also true. # value, the array will be ordered from earliest to latest. The reverse is also true.
def between(from, to) def between(from, to)
from_number, to_number = journal_at(from), journal_at(to) from_number = journal_at(from)
to_number = journal_at(to)
return [] if from_number.nil? || to_number.nil? return [] if from_number.nil? || to_number.nil?
condition = (from_number == to_number) ? to_number : Range.new(*[from_number, to_number].sort) condition = (from_number == to_number) ? to_number : Range.new(*[from_number, to_number].sort)

@ -33,7 +33,8 @@ class ResetTest < Test::Unit::TestCase
context 'Resetting a model' do context 'Resetting a model' do
setup do setup do
@original_dependent = User.reflect_on_association(:journals).options[:dependent] @original_dependent = User.reflect_on_association(:journals).options[:dependent]
@user, @journals = User.new, [] @user = User.new
@journals = []
@names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs'] @names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs']
@names.each do |name| @names.each do |name|
@user.update_attribute(:name, name) @user.update_attribute(:name, name)
@ -49,7 +50,7 @@ class ResetTest < Test::Unit::TestCase
end end
should 'dissociate all journals after the target' do should 'dissociate all journals after the target' do
@journals.reverse.each do |journal| @journals.reverse_each do |journal|
@user.reset_to!(journal) @user.reset_to!(journal)
assert_equal 0, @user.journals(true).after(journal).count assert_equal 0, @user.journals(true).after(journal).count
end end
@ -61,7 +62,7 @@ class ResetTest < Test::Unit::TestCase
end end
should 'delete all journals after the target journal' do should 'delete all journals after the target journal' do
@journals.reverse.each do |journal| @journals.reverse_each do |journal|
later_journals = @user.journals.after(journal) later_journals = @user.journals.after(journal)
@user.reset_to!(journal) @user.reset_to!(journal)
later_journals.each do |later_journal| later_journals.each do |later_journal|
@ -74,7 +75,7 @@ class ResetTest < Test::Unit::TestCase
should 'not destroy all journals after the target journal' do should 'not destroy all journals after the target journal' do
VestalVersions::Version.any_instance.stub(:destroy).and_raise(RuntimeError) VestalVersions::Version.any_instance.stub(:destroy).and_raise(RuntimeError)
@journals.reverse.each do |journal| @journals.reverse_each do |journal|
assert_nothing_raised do assert_nothing_raised do
@user.reset_to!(journal) @user.reset_to!(journal)
end end
@ -88,7 +89,7 @@ class ResetTest < Test::Unit::TestCase
end end
should 'delete all journals after the target journal' do should 'delete all journals after the target journal' do
@journals.reverse.each do |journal| @journals.reverse_each do |journal|
later_journals = @user.journals.after(journal) later_journals = @user.journals.after(journal)
@user.reset_to!(journal) @user.reset_to!(journal)
later_journals.each do |later_journal| later_journals.each do |later_journal|
@ -101,7 +102,7 @@ class ResetTest < Test::Unit::TestCase
should 'destroy all journals after the target journal' do should 'destroy all journals after the target journal' do
VestalVersions::Version.any_instance.stub(:destroy).and_raise(RuntimeError) VestalVersions::Version.any_instance.stub(:destroy).and_raise(RuntimeError)
@journals.reverse.each do |journal| @journals.reverse_each do |journal|
later_journals = @user.journals.after(journal) later_journals = @user.journals.after(journal)
if later_journals.empty? if later_journals.empty?
assert_nothing_raised do assert_nothing_raised do
@ -122,7 +123,7 @@ class ResetTest < Test::Unit::TestCase
end end
should 'leave all journals after the target journal' do should 'leave all journals after the target journal' do
@journals.reverse.each do |journal| @journals.reverse_each do |journal|
later_journals = @user.journals.after(journal) later_journals = @user.journals.after(journal)
@user.reset_to!(journal) @user.reset_to!(journal)
later_journals.each do |later_journal| later_journals.each do |later_journal|

@ -32,7 +32,9 @@ require File.join(File.dirname(__FILE__), 'test_helper')
class RejournalTest < Test::Unit::TestCase class RejournalTest < Test::Unit::TestCase
context 'A model rejournal' do context 'A model rejournal' do
setup do setup do
@user, @attributes, @times = User.new, {}, {} @user = User.new
@attributes = {}
@times = {}
names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs'] names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs']
time = names.size.hours.ago time = names.size.hours.ago
names.each do |name| names.each do |name|
@ -45,7 +47,8 @@ class RejournalTest < Test::Unit::TestCase
@times[@user.journal] = time @times[@user.journal] = time
end end
@user.reload.journals.reload @user.reload.journals.reload
@first_journal, @last_journal = @attributes.keys.min, @attributes.keys.max @first_journal = @attributes.keys.min
@last_journal = @attributes.keys.max
end end
should 'return the new journal number' do should 'return the new journal number' do

@ -35,7 +35,8 @@ class VersionTest < Test::Unit::TestCase
@user = User.create(name: 'Stephen Richert') @user = User.create(name: 'Stephen Richert')
@user.update_attribute(:name, 'Steve Jobs') @user.update_attribute(:name, 'Steve Jobs')
@user.update_attribute(:last_name, 'Richert') @user.update_attribute(:last_name, 'Richert')
@first_journal, @last_journal = @user.journals.first, @user.journals.last @first_journal = @user.journals.first
@last_journal = @user.journals.last
end end
should 'be comparable to another journal based on journal number' do should 'be comparable to another journal based on journal number' do
@ -53,7 +54,8 @@ class VersionTest < Test::Unit::TestCase
user = User.create(name: 'Stephen Richert') user = User.create(name: 'Stephen Richert')
user.update_attribute(:name, 'Steve Jobs') user.update_attribute(:name, 'Steve Jobs')
user.update_attribute(:last_name, 'Richert') user.update_attribute(:last_name, 'Richert')
first_journal, last_journal = user.journals.first, user.journals.last first_journal = user.journals.first
last_journal = user.journals.last
assert_not_equal @first_journal, first_journal assert_not_equal @first_journal, first_journal
assert_not_equal @last_journal, last_journal assert_not_equal @last_journal, last_journal
end end

@ -32,7 +32,8 @@ require File.join(File.dirname(__FILE__), 'test_helper')
class VersionsTest < Test::Unit::TestCase class VersionsTest < Test::Unit::TestCase
context 'A collection of associated journals' do context 'A collection of associated journals' do
setup do setup do
@user, @times = User.new, {} @user = User.new
@times = {}
names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs'] names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs']
time = names.size.hours.ago time = names.size.hours.ago
names.each do |name| names.each do |name|

@ -66,7 +66,8 @@ module ActiveRecord
# #
# subchild1.ancestors # => [child1, root] # subchild1.ancestors # => [child1, root]
def ancestors def ancestors
node, nodes = self, [] node = self
nodes = []
nodes << node = node.parent while node.parent nodes << node = node.parent while node.parent
nodes nodes
end end

@ -149,7 +149,7 @@ module Redmine
# Returns an array of watchers' email addresses # Returns an array of watchers' email addresses
def watcher_recipients def watcher_recipients
notified = watcher_users.active.where(['mail_notification != ?', 'none']) notified = watcher_users.active.where(['mail_notification != ?', 'none'])
notified.select! { |user| possible_watcher?(user) } notified.select! do |user| possible_watcher?(user) end
notified.map(&:mail).compact notified.map(&:mail).compact
end end

@ -51,15 +51,15 @@ module Redmine
@event_types = Redmine::Activity.available_event_types @event_types = Redmine::Activity.available_event_types
if @project if @project
@event_types = @event_types.select do |o| @event_types = @event_types.select { |o|
@project.self_and_descendants.detect do |_p| @project.self_and_descendants.detect do |_p|
permissions = constantized_providers(o).map do |p| permissions = constantized_providers(o).map { |p|
p.activity_provider_options[o].try(:[], :permission) p.activity_provider_options[o].try(:[], :permission)
end.compact }.compact
return @user.allowed_to?("view_#{o}".to_sym, @project) if permissions.blank? return @user.allowed_to?("view_#{o}".to_sym, @project) if permissions.blank?
permissions.all? { |p| @user.allowed_to?(p, @project) } permissions.all? { |p| @user.allowed_to?(p, @project) }
end end
end }
end end
@event_types @event_types
end end
@ -107,7 +107,7 @@ module Redmine
e.project = projects.find { |p| p.id == e.project_id } if e.project_id e.project = projects.find { |p| p.id == e.project_id } if e.project_id
end end
e.sort! { |a, b| b.event_datetime <=> a.event_datetime } e.sort! do |a, b| b.event_datetime <=> a.event_datetime end
e e
end end

@ -40,7 +40,7 @@ module Redmine #:nodoc:
s = $1 s = $1
else else
# 2:30 => 2.5 # 2:30 => 2.5
s.gsub!(%r{^(\d+):(\d+)$}) { $1.to_i + $2.to_i / 60.0 } s.gsub!(%r{^(\d+):(\d+)$}) do $1.to_i + $2.to_i / 60.0 end
# 2h30, 2h, 30m => 2.5, 2, 0.5 # 2h30, 2h, 30m => 2.5, 2, 0.5
s.gsub!(%r{^((\d+)\s*(h|hours?))?\s*((\d+)\s*(m|min)?)?$}) { |m| ($1 || $4) ? ($2.to_i + $5.to_i / 60.0) : m[0] } s.gsub!(%r{^((\d+)\s*(h|hours?))?\s*((\d+)\s*(m|min)?)?$}) { |m| ($1 || $4) ? ($2.to_i + $5.to_i / 60.0) : m[0] }
end end

@ -143,11 +143,11 @@ module Redmine
# Colors # Colors
colors_list = PlanningElementTypeColor.colors colors_list = PlanningElementTypeColor.colors
colors = Hash[*(colors_list.map do |color| colors = Hash[*(colors_list.map { |color|
color.save color.save
color.reload color.reload
[color.name.to_sym, color.id] [color.name.to_sym, color.id]
end).flatten] }).flatten]
# Types # Types
task = ::Type.create! name: l(:default_type_task), task = ::Type.create! name: l(:default_type_task),
@ -250,7 +250,7 @@ module Redmine
phase.id => [new, to_be_scheduled, scheduled, in_progress, on_hold, rejected, closed], phase.id => [new, to_be_scheduled, scheduled, in_progress, on_hold, rejected, closed],
bug.id => [new, confirmed, in_progress, tested, on_hold, rejected, closed], bug.id => [new, confirmed, in_progress, tested, on_hold, rejected, closed],
feature.id => [new, specified, confirmed, in_progress, tested, on_hold, rejected, closed] } feature.id => [new, specified, confirmed, in_progress, tested, on_hold, rejected, closed] }
workflows.each { |type_id, statuses_for_type| workflows.each do |type_id, statuses_for_type|
statuses_for_type.each { |old_status| statuses_for_type.each { |old_status|
statuses_for_type.each { |new_status| statuses_for_type.each { |new_status|
[manager.id, member.id].each { |role_id| [manager.id, member.id].each { |role_id|
@ -261,7 +261,7 @@ module Redmine
} }
} }
} }
} end
# Enumerations # Enumerations
@ -287,9 +287,9 @@ module Redmine
ProjectType.create!(name: l(:default_project_type_internal)) ProjectType.create!(name: l(:default_project_type_internal))
reported_status_ids = ReportedProjectStatus.find(:all).map(&:id) reported_status_ids = ReportedProjectStatus.find(:all).map(&:id)
ProjectType.find(:all).each { |project| ProjectType.find(:all).each do |project|
project.update_attributes(reported_project_status_ids: reported_status_ids) project.update_attributes(reported_project_status_ids: reported_status_ids)
} end
Setting['notified_events'] = ['work_package_added', \ Setting['notified_events'] = ['work_package_added', \
'work_package_updated',\ 'work_package_updated',\

@ -128,9 +128,9 @@ module Redmine
@cached_attribute_translations ||= {} @cached_attribute_translations ||= {}
@cached_attribute_translations[locale] ||= ( @cached_attribute_translations[locale] ||= (
general_attributes = ::I18n.t('attributes', locale: locale) general_attributes = ::I18n.t('attributes', locale: locale)
::I18n.t('activerecord.attributes', locale: locale).inject(general_attributes) do |attr_t, model_t| ::I18n.t('activerecord.attributes', locale: locale).inject(general_attributes) { |attr_t, model_t|
attr_t.merge(model_t.last || {}) attr_t.merge(model_t.last || {})
end) })
@cached_attribute_translations[locale] @cached_attribute_translations[locale]
end end
end end

@ -56,13 +56,13 @@ module Redmine::MenuManager::MenuHelper
param: :project_id, param: :project_id,
caption: main_item.name, caption: main_item.name,
after: :repository, after: :repository,
html: {class: 'icon2 icon-wiki'} html: { class: 'icon2 icon-wiki' }
menu.push :"#{main_item.item_class}_new_page", menu.push :"#{main_item.item_class}_new_page",
{ action:"new_child", controller:"/wiki", id: CGI.escape(main_item.title) }, { action: 'new_child', controller: '/wiki', id: CGI.escape(main_item.title) },
param: :project_id, param: :project_id,
caption: :create_child_page, caption: :create_child_page,
html: {class: 'icon2 icon-add'}, html: { class: 'icon2 icon-add' },
parent: "#{main_item.item_class}".to_sym if main_item.new_wiki_page and parent: "#{main_item.item_class}".to_sym if main_item.new_wiki_page and
WikiPage.find_by(wiki_id: project_wiki.id, title: main_item.title) WikiPage.find_by(wiki_id: project_wiki.id, title: main_item.title)
@ -70,7 +70,7 @@ module Redmine::MenuManager::MenuHelper
{ action: 'index', controller: '/wiki', id: CGI.escape(main_item.title) }, { action: 'index', controller: '/wiki', id: CGI.escape(main_item.title) },
param: :project_id, param: :project_id,
caption: :label_table_of_contents, caption: :label_table_of_contents,
html: {class: 'icon2 icon-list-view1'}, html: { class: 'icon2 icon-list-view1' },
parent: "#{main_item.item_class}".to_sym if main_item.index_page parent: "#{main_item.item_class}".to_sym if main_item.index_page
main_item.children.each do |child| main_item.children.each do |child|
@ -78,7 +78,7 @@ module Redmine::MenuManager::MenuHelper
{ controller: '/wiki', action: 'show', id: CGI.escape(child.title) }, { controller: '/wiki', action: 'show', id: CGI.escape(child.title) },
param: :project_id, param: :project_id,
caption: child.name, caption: child.name,
html: {class: 'icon2 icon-wiki2'}, html: { class: 'icon2 icon-wiki2' },
parent: "#{main_item.item_class}".to_sym parent: "#{main_item.item_class}".to_sym
end end
# FIXME using wiki_menu_item#title to reference the wiki page and wiki_menu_item#name as the menu item representation feels wrong # FIXME using wiki_menu_item#title to reference the wiki page and wiki_menu_item#name as the menu item representation feels wrong
@ -86,13 +86,13 @@ module Redmine::MenuManager::MenuHelper
end end
end end
def build_work_packages_menu(project) def build_work_packages_menu(_project)
query_menu_items = visible_queries.map(&:query_menu_item).compact query_menu_items = visible_queries.map(&:query_menu_item).compact
Redmine::MenuManager.loose :project_menu do |menu| Redmine::MenuManager.loose :project_menu do |menu|
query_menu_items.each do |query_menu_item| query_menu_items.each do |query_menu_item|
# url = project_work_packages_path(project, query_id: query_menu_item.navigatable_id) does not work because the authorization check fails # url = project_work_packages_path(project, query_id: query_menu_item.navigatable_id) does not work because the authorization check fails
url = { controller: '/work_packages', action: 'index', params: {query_id: query_menu_item.navigatable_id} } url = { controller: '/work_packages', action: 'index', params: { query_id: query_menu_item.navigatable_id } }
menu.push query_menu_item.unique_name, menu.push query_menu_item.unique_name,
url, url,
param: :project_id, param: :project_id,
@ -100,7 +100,7 @@ module Redmine::MenuManager::MenuHelper
parent: :work_packages, parent: :work_packages,
html: { html: {
class: 'icon2 icon-pin query-menu-item', class: 'icon2 icon-pin query-menu-item',
"data-ui-route" => '', 'data-ui-route' => '',
'query-menu-item' => 'query-menu-item', 'query-menu-item' => 'query-menu-item',
'object-id' => query_menu_item.navigatable_id 'object-id' => query_menu_item.navigatable_id
} }
@ -113,42 +113,40 @@ module Redmine::MenuManager::MenuHelper
Redmine::MenuManager.items(menu_name).size > 1 # 1 element is the root Redmine::MenuManager.items(menu_name).size > 1 # 1 element is the root
end end
def render_menu(menu, project=nil) def render_menu(menu, project = nil)
links = [] links = []
menu_items_for(menu, project) do |node| menu_items_for(menu, project) do |node|
links << render_menu_node(node, project) links << render_menu_node(node, project)
end end
links.empty? ? nil : content_tag('ul', links.join("\n").html_safe, class: "menu_root") links.empty? ? nil : content_tag('ul', links.join("\n").html_safe, class: 'menu_root')
end end
def render_drop_down_menu_node(label, items_or_options_with_block = nil, html_options = {}, &block) def render_drop_down_menu_node(label, items_or_options_with_block = nil, html_options = {}, &_block)
items, options = if block_given? items, options = if block_given?
[[], items_or_options_with_block || {} ] [[], items_or_options_with_block || {}]
else else
[items_or_options_with_block, html_options] [items_or_options_with_block, html_options]
end end
return "" if items.empty? && !block_given? return '' if items.empty? && !block_given?
options.reverse_merge!({ class: "drop-down" }) options.reverse_merge!(class: 'drop-down')
content_tag :li, options do content_tag :li, options do
label + if block_given? label + if block_given?
yield yield
else else
content_tag :ul, style: "display:none" do content_tag :ul, style: 'display:none' do
items.map { |item|
items.map do |item|
render_menu_node(item) render_menu_node(item)
end.join(" ").html_safe }.join(' ').html_safe
end end
end end
end end
end end
def render_menu_node(node, project=nil) def render_menu_node(node, project = nil)
return "" if project and not allowed_node?(node, User.current, project) return '' if project and not allowed_node?(node, User.current, project)
if node.has_children? || !node.child_menus.nil? if node.has_children? || !node.child_menus.nil?
render_menu_node_with_children(node, project) render_menu_node_with_children(node, project)
else else
@ -157,14 +155,14 @@ module Redmine::MenuManager::MenuHelper
end end
end end
def render_menu_node_with_children(node, project=nil) def render_menu_node_with_children(node, project = nil)
caption, url, selected = extract_node_details(node, project) caption, url, selected = extract_node_details(node, project)
content_tag :li do content_tag :li do
# Standard children # Standard children
standard_children_list = node.children.map do |child| standard_children_list = node.children.map { |child|
render_menu_node(child, project) render_menu_node(child, project)
end.join.html_safe }.join.html_safe
# Unattached children # Unattached children
unattached_children_list = render_unattached_children_menu(node, project) unattached_children_list = render_unattached_children_menu(node, project)
@ -184,7 +182,7 @@ module Redmine::MenuManager::MenuHelper
def render_unattached_children_menu(node, project) def render_unattached_children_menu(node, project)
return nil unless node.child_menus return nil unless node.child_menus
"".tap do |child_html| ''.tap do |child_html|
unattached_children = node.child_menus.call(project) unattached_children = node.child_menus.call(project)
# Tree nodes support #each so we need to do object detection # Tree nodes support #each so we need to do object detection
if unattached_children.is_a? Array if unattached_children.is_a? Array
@ -192,7 +190,7 @@ module Redmine::MenuManager::MenuHelper
child_html << content_tag(:li, render_unattached_menu_item(child, project)) child_html << content_tag(:li, render_unattached_menu_item(child, project))
end end
else else
raise Redmine::MenuManager::MenuError, ":child_menus must be an array of MenuItems" raise Redmine::MenuManager::MenuError, ':child_menus must be an array of MenuItems'
end end
end.html_safe end.html_safe
end end
@ -208,7 +206,7 @@ module Redmine::MenuManager::MenuHelper
end end
def render_unattached_menu_item(menu_item, project) def render_unattached_menu_item(menu_item, project)
raise Redmine::MenuManager::MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? Redmine::MenuManager::MenuItem raise Redmine::MenuManager::MenuError, ':child_menus must be an array of MenuItems' unless menu_item.is_a? Redmine::MenuManager::MenuItem
if User.current.allowed_to?(menu_item.url, project) if User.current.allowed_to?(menu_item.url, project)
link_to(menu_item.caption, link_to(menu_item.caption,
@ -217,7 +215,7 @@ module Redmine::MenuManager::MenuHelper
end end
end end
def menu_items_for(menu, project=nil) def menu_items_for(menu, project = nil)
items = [] items = []
Redmine::MenuManager.items(menu).root.children.each do |node| Redmine::MenuManager.items(menu).root.children.each do |node|
if allowed_node?(node, User.current, project) && visible_node?(menu, node) if allowed_node?(node, User.current, project) && visible_node?(menu, node)
@ -228,14 +226,14 @@ module Redmine::MenuManager::MenuHelper
end end
end end
end end
return block_given? ? nil : items block_given? ? nil : items
end end
def extract_node_details(node, project=nil) def extract_node_details(node, project = nil)
item = node item = node
url = case item.url url = case item.url
when Hash when Hash
project.nil? ? item.url : {item.param => project}.merge(item.url) project.nil? ? item.url : { item.param => project }.merge(item.url)
when Symbol when Symbol
send(item.url) send(item.url)
else else
@ -245,7 +243,7 @@ module Redmine::MenuManager::MenuHelper
selected = current_menu_item == item.name selected = current_menu_item == item.name
return [caption, url, selected] [caption, url, selected]
end end
# Checks if a user is allowed to access the menu item by: # Checks if a user is allowed to access the menu item by:

@ -142,9 +142,9 @@ module Redmine::MenuManager::TopMenuHelper
end end
def render_main_top_menu_nodes(items = main_top_menu_items) def render_main_top_menu_nodes(items = main_top_menu_items)
items.map do |item| items.map { |item|
render_menu_node(item) render_menu_node(item)
end.join(' ') }.join(' ')
end end
# Menu items for the main top menu # Menu items for the main top menu

@ -81,10 +81,10 @@ module Redmine
'video/x-msvideo' => 'avi', 'video/x-msvideo' => 'avi',
}.freeze }.freeze
EXTENSIONS = MIME_TYPES.inject({}) do |map, (type, exts)| EXTENSIONS = MIME_TYPES.inject({}) { |map, (type, exts)|
exts.split(',').each { |ext| map[ext.strip] = type } exts.split(',').each do |ext| map[ext.strip] = type end
map map
end }
# returns mime type for name or nil if unknown # returns mime type for name or nil if unknown
def self.of(name) def self.of(name)

@ -303,7 +303,7 @@ module Redmine #:nodoc:
# permission :say_hello, { :example => :say_hello }, :require => :member # permission :say_hello, { :example => :say_hello }, :require => :member
def permission(name, actions, options = {}) def permission(name, actions, options = {})
if @project_module if @project_module
Redmine::AccessControl.map { |map| map.project_module(@project_module) { |map|map.permission(name, actions, options) } } Redmine::AccessControl.map { |map| map.project_module(@project_module) { |map| map.permission(name, actions, options) } }
else else
Redmine::AccessControl.map { |map| map.permission(name, actions, options) } Redmine::AccessControl.map { |map| map.permission(name, actions, options) }
end end

@ -156,7 +156,7 @@ module Redmine
cmd_args << rev if rev cmd_args << rev if rev
cmd_args << '--' << path unless path.empty? cmd_args << '--' << path unless path.empty?
lines = [] lines = []
scm_cmd(*cmd_args) { |io| lines = io.readlines } scm_cmd(*cmd_args) do |io| lines = io.readlines end
begin begin
id = lines[0].split[1] id = lines[0].split[1]
author = lines[1].match('Author:\s+(.*)$')[1] author = lines[1].match('Author:\s+(.*)$')[1]
@ -230,15 +230,13 @@ module Redmine
elsif (parsing_descr == 0) && line.chomp.to_s == '' elsif (parsing_descr == 0) && line.chomp.to_s == ''
parsing_descr = 1 parsing_descr = 1
changeset[:description] = '' changeset[:description] = ''
elsif (parsing_descr == 1 || parsing_descr == 2) \ elsif (parsing_descr == 1 || parsing_descr == 2) && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\t(.+)$/
&& line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\t(.+)$/
parsing_descr = 2 parsing_descr = 2
fileaction = $1 fileaction = $1
filepath = $2 filepath = $2
p = scm_encode('UTF-8', @path_encoding, filepath) p = scm_encode('UTF-8', @path_encoding, filepath)
files << { action: fileaction, path: p } files << { action: fileaction, path: p }
elsif (parsing_descr == 1 || parsing_descr == 2) \ elsif (parsing_descr == 1 || parsing_descr == 2) && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\t(.+)$/
&& line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\t(.+)$/
parsing_descr = 2 parsing_descr = 2
fileaction = $1 fileaction = $1
filepath = $3 filepath = $3
@ -299,7 +297,7 @@ module Redmine
cmd_args << '-p' << identifier << '--' << scm_encode(@path_encoding, 'UTF-8', path) cmd_args << '-p' << identifier << '--' << scm_encode(@path_encoding, 'UTF-8', path)
blame = Annotate.new blame = Annotate.new
content = nil content = nil
scm_cmd(*cmd_args) { |io| io.binmode; content = io.read } scm_cmd(*cmd_args) do |io| io.binmode; content = io.read end
# git annotates binary files # git annotates binary files
if content.respond_to?('is_binary_data?') && content.is_binary_data? # Ruby 1.8.x and <1.9.2 if content.respond_to?('is_binary_data?') && content.is_binary_data? # Ruby 1.8.x and <1.9.2
return nil return nil

@ -192,7 +192,7 @@ module Redmine
from_revision: path['copyfrom-rev'] from_revision: path['copyfrom-rev']
} }
end if logentry['paths'] && logentry['paths']['path'] end if logentry['paths'] && logentry['paths']['path']
paths.sort! { |x, y| x[:path] <=> y[:path] } paths.sort! do |x, y| x[:path] <=> y[:path] end
revisions << Revision.new(identifier: logentry['revision'], revisions << Revision.new(identifier: logentry['revision'],
author: (logentry['author'] ? logentry['author']['__content__'] : ''), author: (logentry['author'] ? logentry['author']['__content__'] : ''),

@ -105,7 +105,8 @@ module Redmine
end end
def each_line def each_line
prev_line_left, prev_line_right = nil, nil prev_line_left = nil
prev_line_right = nil
each do |line| each do |line|
spacing = prev_line_left && prev_line_right && (line.nb_line_left != prev_line_left + 1) && (line.nb_line_right != prev_line_right + 1) spacing = prev_line_left && prev_line_right && (line.nb_line_left != prev_line_left + 1) && (line.nb_line_right != prev_line_right + 1)
yield spacing, line yield spacing, line

@ -34,23 +34,22 @@ module Redmine
def self.additional_blocks def self.additional_blocks
# look at the gemspecs of all plugins trying to find views in a /my/blocks subdirectory # look at the gemspecs of all plugins trying to find views in a /my/blocks subdirectory
@@additional_blocks ||= Dir.glob( @@additional_blocks ||= Dir.glob(
Plugin.registered_plugins.map do |plugin_id, _| Plugin.registered_plugins.map { |plugin_id, _|
gem_name = plugin_id.to_s.gsub('openproject_', 'openproject-') if plugin_id.to_s.starts_with?('openproject_') gem_name = plugin_id.to_s.gsub('openproject_', 'openproject-') if plugin_id.to_s.starts_with?('openproject_')
gem_spec = Gem.loaded_specs[gem_name] gem_spec = Gem.loaded_specs[gem_name]
if gem_spec.nil? if gem_spec.nil?
error = 'No Gemspec found for plugin: ' + plugin_id.to_s \ error = 'No Gemspec found for plugin: ' + plugin_id.to_s + ', expected gem name to match the plugin name but starting with openproject-'
+ ', expected gem name to match the plugin name but starting with openproject-'
ActiveSupport::Deprecation.warn(error) ActiveSupport::Deprecation.warn(error)
nil nil
else else
gem_spec.full_gem_path + '/app/views/my/blocks/_*.{rhtml,erb}' gem_spec.full_gem_path + '/app/views/my/blocks/_*.{rhtml,erb}'
end end
end.compact }.compact
).inject({}) do |h, file| ).inject({}) { |h, file|
name = File.basename(file).split('.').first.gsub(/\A_/, '') name = File.basename(file).split('.').first.gsub(/\A_/, '')
h[name] = ('label_' + name).to_sym h[name] = ('label_' + name).to_sym
h h
end }
end end
end end
end end

@ -97,7 +97,9 @@ module Redmine
# Macros substitution # Macros substitution
def execute_macros(text, macros_runner) def execute_macros(text, macros_runner)
text.gsub!(MACROS_RE) do text.gsub!(MACROS_RE) do
esc, all, macro = $1, $2, $3.downcase esc = $1
all = $2
macro = $3.downcase
args = ($5 || '').split(',').each(&:strip!) args = ($5 || '').split(',').each(&:strip!)
if esc.nil? if esc.nil?
begin begin

@ -97,7 +97,11 @@ module Redmine
# Turns all urls into clickable links (code from Rails). # Turns all urls into clickable links (code from Rails).
def inline_auto_link(text) def inline_auto_link(text)
text.gsub!(AUTO_LINK_RE) do text.gsub!(AUTO_LINK_RE) do
all, leading, proto, url, post = $&, $1, $2, $3, $6 all = $&
leading = $1
proto = $2
url = $3
post = $6
if leading =~ /<a\s/i || leading =~ /![<>=]?/ || leading =~ /\{\{\w+\(/ if leading =~ /<a\s/i || leading =~ /![<>=]?/ || leading =~ /\{\{\w+\(/
# don't replace URLs that are already linked # don't replace URLs that are already linked
# and URLs prefixed with ! !> !< != (textile images) # and URLs prefixed with ! !> !< != (textile images)

@ -132,7 +132,7 @@ class TabularFormBuilder < ActionView::Helpers::FormBuilder
end end
def localize_field(field, options, meth) def localize_field(field, options, meth)
localized_field = Proc.new do |translation_form, multiple| localized_field = Proc.new do |translation_form, _multiple|
localized_field(translation_form, meth, field, options) localized_field(translation_form, meth, field, options)
end end
@ -203,7 +203,7 @@ class TabularFormBuilder < ActionView::Helpers::FormBuilder
id.sub(/\_id$/, "_#{field}") id.sub(/\_id$/, "_#{field}")
end end
label_options[:lang] = options[:lang] label_options[:lang] = options[:lang]
label_options.reject! { |_k, v| v.nil? } label_options.reject! do |_k, v| v.nil? end
@template.label(@object_name, field, h(text), label_options) @template.label(@object_name, field, h(text), label_options)
end end
@ -262,9 +262,9 @@ class TabularFormBuilder < ActionView::Helpers::FormBuilder
object.translations.build locale: user_locale object.translations.build locale: user_locale
object.translations object.translations
else else
translations = object.translations.select do |t| translations = object.translations.select { |t|
t.send(field).present? t.send(field).present?
end }
if translations.size > 0 if translations.size > 0
translations translations

Loading…
Cancel
Save