Skip to content

Commit

Permalink
Implements all the non-custom-fields tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
mereghost committed Dec 24, 2024
1 parent 8636fa3 commit a34c017
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 37 deletions.
2 changes: 1 addition & 1 deletion app/models/types/pattern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ module Types
def enabled? = !!enabled

def resolve(work_package)
PatternMapper.new(self).resolve(work_package)
PatternResolver.new(blueprint).resolve(work_package)
end

def to_h
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,16 @@
#++

module Types
class PatternMapper
class PatternResolver
TOKEN_REGEX = /{{[0-9A-Za-z_]+}}/

MAPPING = {
type: ->(wp) { wp.type.name },
assignee: ->(wp) { wp.assigned_to&.name },
created: ->(wp) { wp.created_at },
author: ->(wp) { wp.author.name },
parent_id: ->(wp) { wp.parent&.id },
project_name: ->(wp) { wp.project.name }
}.freeze

private_constant :MAPPING
private_constant :TOKEN_REGEX

def initialize(pattern)
@mapper = Patterns::TokenPropertyMapper.new
@pattern = pattern
@tokens = pattern.scan(TOKEN_REGEX).map { |token| Patterns::Token.build(token) }
end

def valid?(work_package)
@tokens.each { |token| get_value(work_package, token) }
rescue NoMethodError
false
end

def resolve(work_package)
@tokens.inject(@pattern) do |pattern, token|
pattern.gsub(token.pattern, get_value(work_package, token))
Expand All @@ -63,17 +48,13 @@ def resolve(work_package)
private

def get_value(work_package, token)
raw_value = if token.custom_field? && token.context != work_package.context
fn(key).call(work_package.public_send(token.context))
else
fn(token.key).call(work_package)
end

stringify(raw_value)
end
context = if token.custom_field_context == :work_package
work_package
else
work_package.public_send(token.context)
end

def fn(key)
MAPPING.fetch(key) { ->(wp) { wp.public_send(key.to_sym) } }
stringify(@mapper[token.key].call(context))
end

def stringify(value)
Expand Down
8 changes: 2 additions & 6 deletions app/models/types/patterns/token.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,9 @@ def self.build(pattern)

def custom_field? = key.to_s.include?("custom_field")

def custom_field_id
return nil unless custom_field?
def context
return :work_package unless custom_field?

Integer(key.to_s.gsub(/\D+/, ""))
end

def custom_field_context
context = key.to_s.gsub(/_?custom_field_\d+/, "")
return :work_package if context.blank?

Expand Down
75 changes: 75 additions & 0 deletions app/models/types/patterns/token_property_mapper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 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 Types
module Patterns
class TokenPropertyMapper
MAPPING = {
accountable: ->(wp) { wp.responsible&.name },
assignee: ->(wp) { wp.assigned_to&.name },
author: ->(wp) { wp.author&.name },
category: ->(wp) { wp.category&.name },
creation_date: ->(wp) { wp.created_at },
estimated_time: ->(wp) { wp.estimated_hours },
finish_date: ->(wp) { wp.due_date },
parent: ->(wp) { wp.parent&.id },
parent_author: ->(wp) { wp.parent&.author&.name },
parent_category: ->(wp) { wp.parent&.category&.name },
parent_creation_date: ->(wp) { wp.parent&.created_at },
parent_estimated_time: ->(wp) { wp.parent&.estimated_hours },
parent_finish_date: ->(wp) { wp.parent&.due_date },
parent_priority: ->(wp) { wp.parent&.priority },
priority: ->(wp) { wp.priority },
project: ->(wp) { wp.project_id },
project_active: ->(wp) { wp.project&.active? },
project_name: ->(wp) { wp.project&.name },
project_status: ->(wp) { wp.project&.status_code },
project_parent: ->(wp) { wp.project&.parent_id },
project_public: ->(wp) { wp.project&.public? },
start_date: ->(wp) { wp.start_date },
status: ->(wp) { wp.status&.name },
type: ->(wp) { wp.type&.name }
}.freeze

def fetch(key)
MAPPING.fetch(key) { ->(context) { context.public_send(key.to_sym) } }
end

alias :[] :fetch

def tokens_for_type(_type)
[]
# Fetch all CustomFields for type
# Fetch all customFields prefixed as parent
# fetch all project attributes prefixed as project
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

require "spec_helper"

RSpec.describe Types::PatternMapper do
RSpec.describe Types::PatternResolver do
let(:subject_pattern) { "ID Please: {{id}}" }
let(:work_package) { create(:work_package) }

Expand All @@ -41,7 +41,7 @@
end

context "when the pattern has WorkPackage properties" do
let(:subject_pattern) { "{{id}} | {{done_ratio}} | {{created}}" }
let(:subject_pattern) { "{{id}} | {{done_ratio}} | {{creation_date}}" }

it "resolves the pattern" do
expect(subject.resolve(work_package))
Expand Down
55 changes: 55 additions & 0 deletions spec/models/types/patterns/token_property_mapper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 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.
#++

require "spec_helper"

RSpec.describe Types::Patterns::TokenPropertyMapper do
shared_let(:responsible) { create(:user, firstname: "Responsible") }
shared_let(:assignee) { create(:user, firstname: "Assignee") }

shared_let(:category) { create(:category) }

shared_let(:project) { create(:project, parent: create(:project), status_code: 1, status_explanation: "A Mess") }

shared_let(:work_package_parent) do
create(:work_package, project:, category:, start_date: Date.yesterday, estimated_hours: 120, due_date: 3.months.from_now)
end
shared_let(:work_package) do
create(:work_package, responsible:, project:, category:, due_date: 1.month.from_now,
assigned_to: assignee, parent: work_package_parent, start_date: Time.zone.today, estimated_hours: 30)
end

described_class::MAPPING.each_pair do |key, fn|
it "the token named #{key} resolves successfully" do
expect { fn.call(work_package) }.not_to raise_error
expect(fn.call(work_package)).not_to be_nil
end
end
end

0 comments on commit a34c017

Please sign in to comment.