Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/release/14.0' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
ulferts committed Apr 22, 2024
2 parents dd100d0 + 0eba252 commit 9b4466d
Show file tree
Hide file tree
Showing 37 changed files with 483 additions and 168 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Expand Up @@ -164,7 +164,7 @@ gem "meta-tags", "~> 2.21.0"

gem "paper_trail", "~> 15.1.0"

gem "clamav-client", github: "honestica/clamav-client", ref: "29e78ae94307cb34e79ddd29c5da79752239d8b7"
gem "op-clamav-client", "~> 3.4", require: "clamav"

group :production do
# we use dalli as standard memcache client
Expand Down
10 changes: 2 additions & 8 deletions Gemfile.lock
Expand Up @@ -6,13 +6,6 @@ GIT
capybara_accessible_selectors (0.11.0)
capybara (~> 3.36)

GIT
remote: https://github.com/honestica/clamav-client.git
revision: 29e78ae94307cb34e79ddd29c5da79752239d8b7
ref: 29e78ae94307cb34e79ddd29c5da79752239d8b7
specs:
clamav-client (3.4.2)

GIT
remote: https://github.com/opf/md-to-pdf
revision: 8f14736a88ad0064d2a97be108fe7061ffbcee91
Expand Down Expand Up @@ -760,6 +753,7 @@ GEM
omniauth-saml (1.10.3)
omniauth (~> 1.3, >= 1.3.2)
ruby-saml (~> 1.9)
op-clamav-client (3.4.2)
open4 (1.3.4)
openid_connect (2.2.1)
activemodel
Expand Down Expand Up @@ -1191,7 +1185,6 @@ DEPENDENCIES
capybara_accessible_selectors!
carrierwave (~> 1.3.1)
carrierwave_direct (~> 2.1.0)
clamav-client!
climate_control
closure_tree (~> 7.4.0)
colored2
Expand Down Expand Up @@ -1257,6 +1250,7 @@ DEPENDENCIES
omniauth-openid-connect!
omniauth-openid_connect-providers!
omniauth-saml (~> 1.10.1)
op-clamav-client (~> 3.4)
openproject-auth_plugins!
openproject-auth_saml!
openproject-avatars!
Expand Down
93 changes: 5 additions & 88 deletions app/controllers/queries/params_parser.rb
Expand Up @@ -41,7 +41,11 @@ def parse(params)
private

def parse_filters_from_params(params)
FilterParser.new(params[:filters]).parse
if params[:filters].present? && params[:filters].start_with?("[")
::Queries::ParamsParser::APIV3FiltersParser.parse(params[:filters])
else
FiltersParser.new(params[:filters]).parse
end
end

def parse_orders_from_params(params)
Expand All @@ -56,92 +60,5 @@ def parse_columns_from_params(params)
params[:columns].split
end
end

class FilterParser
def initialize(string)
@buffer = StringScanner.new(string)
end

def parse
filters = []

while !@buffer.eos?
filters << parse_filter
end

filters
end

private

def parse_filter
consume_ampersand

{
attribute: parse_name,
operator: parse_operator,
values: parse_values
}
end

def consume_ampersand
case @buffer.peek(1)
when "&", /\s/
@buffer.getch
consume_ampersand
end
end

def parse_name
@buffer.scan_until(/\s|\z/).strip
end

def parse_operator
@buffer.scan_until(/\s|\z/).strip
end

def parse_values
case @buffer.peek(1)
when '"'
parse_doublequoted_value
when "'"
parse_singlequoted_value
when "["
parse_array_value
when "&"
[]
else
parse_unguarded_value
end
end

def parse_doublequoted_value
@buffer.getch
[@buffer.scan_until(/(?<!\\)"|\z/).delete_suffix('"').delete("\\")]
end

def parse_singlequoted_value
@buffer.getch
[@buffer.scan_until(/(?<!\\)'|\z/).delete_suffix("'").delete("\\")]
end

def parse_unguarded_value
value = @buffer
.scan_until(/&|\z/)
.delete_suffix("&")

[value]
end

def parse_array_value
@buffer
.scan_until(/]|\z/)
.delete_suffix("]")
.delete_prefix("[")
.scan(/(?:'([^']*)')|(?:"([^"]*)")/)
.flatten
.compact
end
end
end
end
47 changes: 47 additions & 0 deletions app/controllers/queries/params_parser/api_v3_filters_parser.rb
@@ -0,0 +1,47 @@
# -- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2010-2024 the OpenProject GmbH
#
# 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-2013 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 COPYRIGHT and LICENSE files for more details.
# ++
module Queries
class ParamsParser
class APIV3FiltersParser
class << self
def parse(filters_string)
filters = JSON.parse(filters_string)

filters.map do |filter|
attribute = filter.keys.first # there should only be one attribute per filter
{
attribute:,
operator: filter[attribute]["operator"],
values: filter[attribute]["values"]
}
end
end
end
end
end
end
117 changes: 117 additions & 0 deletions app/controllers/queries/params_parser/filters_parser.rb
@@ -0,0 +1,117 @@
# -- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2010-2024 the OpenProject GmbH
#
# 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-2013 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 COPYRIGHT and LICENSE files for more details.
# ++
module Queries
class ParamsParser
class FiltersParser
def initialize(string)
@buffer = StringScanner.new(string)
end

def parse
filters = []

while !@buffer.eos?
filters << parse_filter
end

filters
end

private

def parse_filter
consume_ampersand

{
attribute: parse_name,
operator: parse_operator,
values: parse_values
}
end

def consume_ampersand
case @buffer.peek(1)
when "&", /\s/
@buffer.getch
consume_ampersand
end
end

def parse_name
@buffer.scan_until(/\s|\z/).strip
end

def parse_operator
@buffer.scan_until(/\s|\z/).strip
end

def parse_values
case @buffer.peek(1)
when '"'
parse_doublequoted_value
when "'"
parse_singlequoted_value
when "["
parse_array_value
when "&"
[]
else
parse_unguarded_value
end
end

def parse_doublequoted_value
@buffer.getch
[@buffer.scan_until(/(?<!\\)"|\z/).delete_suffix('"').delete("\\")]
end

def parse_singlequoted_value
@buffer.getch
[@buffer.scan_until(/(?<!\\)'|\z/).delete_suffix("'").delete("\\")]
end

def parse_unguarded_value
value = @buffer
.scan_until(/&|\z/)
.delete_suffix("&")

[value]
end

def parse_array_value
@buffer
.scan_until(/]|\z/)
.delete_suffix("]")
.delete_prefix("[")
.scan(/(?:'([^']*)')|(?:"([^"]*)")/)
.flatten
.compact
end
end
end
end
5 changes: 4 additions & 1 deletion app/models/type/attribute_groups.rb
Expand Up @@ -41,11 +41,11 @@ module Type::AttributeGroups
# May be extended by plugins
mattr_accessor :default_group_map do
{
author: :people,
assignee: :people,
responsible: :people,
estimated_time: :estimates_and_time,
remaining_time: :estimates_and_time,
percentage_done: :estimates_and_time,
spent_time: :estimates_and_time,
priority: :details
}
Expand Down Expand Up @@ -117,6 +117,7 @@ def attribute_groups=(groups)
# the default group map.
def default_attribute_groups
values = work_package_attributes_by_default_group_key
values.reject! { |k, _| k == :estimates_and_time } if is_milestone?

default_groups.keys.each_with_object([]) do |groupkey, array|
members = values[groupkey]
Expand Down Expand Up @@ -167,9 +168,11 @@ def default_group_key(key)
# it will put them into the other group.
def work_package_attributes_by_default_group_key
active_cfs = active_custom_field_attributes

work_package_attributes
.keys
.select { |key| default_attribute?(active_cfs, key) }
.sort_by { |key| default_group_map.keys.index(key.to_sym) || default_group_map.keys.size }
.group_by { |key| default_group_key(key.to_sym) }
end

Expand Down
13 changes: 9 additions & 4 deletions app/services/base_type_service.rb
Expand Up @@ -71,12 +71,13 @@ def update(params, options)
def set_params_and_validate(params)
# Only set attribute groups when it exists
# (Regression #28400)
unless params[:attribute_groups].nil?
set_attribute_groups(params)
end
set_attribute_groups(params) unless params[:attribute_groups].nil?

# This should go before `set_scalar_params` call to get the
# project_ids, custom_field_ids diffs from the type and the params
# project_ids, custom_field_ids diffs from the type and the params.
# For determining the active custom fields for the type, it is necessary
# to know whether the type is a milestone or not.
set_milestone_param(params) unless params[:is_milestone].nil?
set_active_custom_fields

if params[:project_ids].present?
Expand All @@ -88,6 +89,10 @@ def set_params_and_validate(params)
validate_and_save(type, user)
end

def set_milestone_param(params)
type.is_milestone = params[:is_milestone]
end

def set_scalar_params(params)
type.attributes = params.except(:attribute_groups)
end
Expand Down

0 comments on commit 9b4466d

Please sign in to comment.