diff --git a/app/contracts/work_packages/base_contract.rb b/app/contracts/work_packages/base_contract.rb index e70f7965356..d869233ae08 100644 --- a/app/contracts/work_packages/base_contract.rb +++ b/app/contracts/work_packages/base_contract.rb @@ -269,10 +269,19 @@ module WorkPackages end def invalid_relations_with_new_hierarchy - Relation - .from_parent_to_self_and_descendants(model) - .or(Relation.from_self_and_descendants_to_ancestors(model)) - .direct + query = Relation.from_parent_to_self_and_descendants(model) + .or(Relation.from_self_and_descendants_to_ancestors(model)) + .direct + + # Ignore the immediate relation from the old parent to the model + # since that will still exist before saving. + old_parent_id = model.parent_id_was + + if old_parent_id.present? + query.where.not(hierarchy: 1, from_id: old_parent_id, to_id: model.id) + else + query + end end end end diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index cd79f694904..11c4cf98323 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -30,8 +30,22 @@ module AccountsHelper end def registration_footer - footer = Setting.registration_footer[I18n.locale.to_s].presence + footer = registration_footer_for lang: I18n.locale.to_s Footer.new(footer).to_html if footer end + + ## + # Gets the registration footer in the given language. + # If registration footers are defined via the OpenProject configuration + # then any footers defined via settings will be ignored. + # + # @param lang [String] ISO 639-1 language code (e.g. 'en', 'de') + def registration_footer_for(lang:) + if footer = OpenProject::Configuration.registration_footer.presence + footer[lang.to_s].presence + else + Setting.registration_footer[lang.to_s].presence + end + end end diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index e73825098ad..4e75ce12522 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -40,6 +40,12 @@ module RepositoriesHelper end end + ## + # Format revision commits with plain formatter + def format_revision_text(commit_message) + format_text(commit_message, format: 'plain') + end + def truncate_at_line_break(text, length = 255) if text text.gsub(%r{^(.{#{length}}[^\n]*)\n.+$}m, '\\1...') diff --git a/app/models/permitted_params.rb b/app/models/permitted_params.rb index 032aa45ab66..6190e720fa4 100644 --- a/app/models/permitted_params.rb +++ b/app/models/permitted_params.rb @@ -27,6 +27,8 @@ # See docs/COPYRIGHT.rdoc for more details. #++ +require 'permitted_params/allowed_settings' + class PermittedParams # This class intends to provide a method for all params hashes coming from the # client and that are used for mass assignment. @@ -180,18 +182,7 @@ class PermittedParams def settings permitted_params = params.require(:settings).permit - - all_setting_keys = Setting.available_settings.keys - all_valid_keys = if OpenProject::Configuration.disable_password_login? - all_setting_keys - %w(password_min_length - password_active_rules - password_min_adhered_rules - password_days_valid - password_count_former_banned - lost_password) - else - all_setting_keys - end + all_valid_keys = AllowedSettings.all permitted_params.merge(params[:settings].to_unsafe_hash.slice(*all_valid_keys)) end diff --git a/app/models/permitted_params/allowed_settings.rb b/app/models/permitted_params/allowed_settings.rb new file mode 100644 index 00000000000..af04a69bb81 --- /dev/null +++ b/app/models/permitted_params/allowed_settings.rb @@ -0,0 +1,65 @@ +class PermittedParams + module AllowedSettings + class Restriction + attr_reader :restricted_keys, :condition + + def initialize(restricted_keys, condition) + @restricted_keys = restricted_keys + @condition = condition + end + + def applicable? + if condition.respond_to? :call + condition.call + else + condition + end + end + end + + module_function + + def all + keys = Setting.available_settings.keys + + restrictions.select(&:applicable?).each do |restriction| + restricted_keys = restriction.restricted_keys + + keys.delete_if { |key| restricted_keys.include? key } + end + + keys + end + + def add_restriction!(keys:, condition:) + restrictions << Restriction.new(keys, condition) + end + + def restrictions + @restrictions ||= [] + end + + def init! + password_keys = %w( + password_min_length + password_active_rules + password_min_adhered_rules + password_days_valid + password_count_former_banned + lost_password + ) + + add_restriction!( + keys: password_keys, + condition: -> { OpenProject::Configuration.disable_password_login? } + ) + + add_restriction!( + keys: %w(registration_footer), + condition: -> { OpenProject::Configuration.registration_footer.present? } + ) + end + + init! + end +end diff --git a/app/models/work_package/scheduling_rules.rb b/app/models/work_package/scheduling_rules.rb index 610f231de94..40790e278bf 100644 --- a/app/models/work_package/scheduling_rules.rb +++ b/app/models/work_package/scheduling_rules.rb @@ -57,9 +57,15 @@ module WorkPackage::SchedulingRules # B is 2017/07/25 # A is 2017/07/25 def soonest_start + # Using a hand crafted union here instead of the alternative + # Relation.from_work_package_or_ancestors(self).follows + # as the performance of the above would be several orders of magnitude worse on MySql + sql = Relation.connection.unprepared_statement do + "((#{ancestors_follows_relations.to_sql}) UNION (#{own_follows_relations.to_sql})) AS relations" + end + @soonest_start ||= - Relation.from_work_package_or_ancestors(self) - .follows + Relation.from(sql) .map(&:successor_soonest_start) .compact .max @@ -79,4 +85,14 @@ module WorkPackage::SchedulingRules 1 end end + + private + + def ancestors_follows_relations + Relation.where(from_id: self.ancestors_relations.select(:from_id)).follows + end + + def own_follows_relations + Relation.where(from_id: self.id).follows + end end diff --git a/app/views/repositories/_revisions.html.erb b/app/views/repositories/_revisions.html.erb index 20c2298af26..b208ed0560a 100644 --- a/app/views/repositories/_revisions.html.erb +++ b/app/views/repositories/_revisions.html.erb @@ -142,7 +142,7 @@ See docs/COPYRIGHT.rdoc for more details. <%=h changeset.author %>
<% if @changeset.scmid %>ID: <%= h(@changeset.scmid) %>
<% end %>