Skip to content

Commit a91efed

Browse files
author
Andreas Pfohl
authored
Merge pull request opf#16884 from opf/implementation/58105-item-persistence-service
Implementation/58105 item persistence service
2 parents 44714ee + 06599b2 commit a91efed

File tree

9 files changed

+626
-0
lines changed

9 files changed

+626
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
module CustomFields
32+
module Hierarchy
33+
class GenerateRootContract < Dry::Validation::Contract
34+
params do
35+
required(:hierarchy_root)
36+
end
37+
38+
rule(:hierarchy_root) do
39+
key.failure("Hierarchical root already set") unless value.nil?
40+
end
41+
end
42+
end
43+
end
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
module CustomFields
32+
module Hierarchy
33+
class InsertItemContract < Dry::Validation::Contract
34+
params do
35+
required(:parent).filled
36+
required(:label).filled(:string)
37+
optional(:short).filled(:string)
38+
end
39+
40+
rule(:parent) do
41+
if value.is_a?(CustomField::Hierarchy::Item)
42+
unless value.persisted?
43+
key.failure("Parent must exist")
44+
end
45+
else
46+
key.failure("Parent must be of type 'Item'")
47+
end
48+
end
49+
50+
rule(:label) do
51+
if CustomField::Hierarchy::Item.exists?(parent_id: values[:parent], label: value)
52+
key.failure("Label must be unique within the same hierarchy level")
53+
end
54+
end
55+
end
56+
end
57+
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
module CustomFields
32+
module Hierarchy
33+
class ServiceInitializationContract < Dry::Validation::Contract
34+
params do
35+
required(:field_format).filled(:string)
36+
end
37+
38+
rule(:field_format) do
39+
key.failure("Custom field must have field format 'hierarchy'") if value != "hierarchy"
40+
end
41+
end
42+
end
43+
end
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
module CustomFields
32+
module Hierarchy
33+
class HierarchicalItemService
34+
include Dry::Monads[:result]
35+
36+
def initialize(custom_field)
37+
validation = ServiceInitializationContract.new.call(field_format: custom_field.field_format)
38+
# rubocop:disable Rails/DeprecatedActiveModelErrorsMethods
39+
raise ArgumentError, "Invalid custom field: #{validation.errors.to_h}" if validation.failure?
40+
# rubocop:enable Rails/DeprecatedActiveModelErrorsMethods
41+
42+
@custom_field = custom_field
43+
end
44+
45+
def generate_root
46+
CustomFields::Hierarchy::GenerateRootContract
47+
.new
48+
.call(hierarchy_root: @custom_field.hierarchy_root)
49+
.to_monad
50+
.bind { create_root_item }
51+
end
52+
53+
def insert_item(parent:, label:, short: nil)
54+
CustomFields::Hierarchy::InsertItemContract
55+
.new
56+
.call({ parent:, label:, short: }.compact)
57+
.to_monad
58+
.bind { |validation| create_child_item(validation) }
59+
end
60+
61+
private
62+
63+
def create_root_item
64+
item = CustomField::Hierarchy::Item.create(custom_field: @custom_field)
65+
return Failure(item.errors) unless item.persisted?
66+
67+
Success(item)
68+
end
69+
70+
def create_child_item(validation)
71+
item = CustomField::Hierarchy::Item
72+
.create(parent: validation[:parent], label: validation[:label], short: validation[:short])
73+
return Failure(item.errors) unless item.persisted?
74+
75+
Success(item)
76+
end
77+
end
78+
end
79+
end
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
require "rails_helper"
32+
33+
RSpec.describe CustomFields::Hierarchy::GenerateRootContract do
34+
subject { described_class.new }
35+
36+
describe "#call" do
37+
context "when hierarchy_root is nil" do
38+
let(:custom_field) { create(:custom_field, field_format: "hierarchy", hierarchy_root: nil) }
39+
40+
it "is valid" do
41+
result = subject.call(hierarchy_root: custom_field.hierarchy_root)
42+
expect(result).to be_success
43+
end
44+
end
45+
46+
context "when hierarchy_root is not nil" do
47+
let(:hierarchy_root) { create(:hierarchy_item) }
48+
let(:custom_field) { create(:custom_field, field_format: "hierarchy", hierarchy_root:) }
49+
50+
it "is invalid" do
51+
result = subject.call(hierarchy_root: custom_field.hierarchy_root)
52+
expect(result).to be_failure
53+
# rubocop:disable Rails/DeprecatedActiveModelErrorsMethods
54+
expect(result.errors.to_h).to include(hierarchy_root: ["Hierarchical root already set"])
55+
# rubocop:enable Rails/DeprecatedActiveModelErrorsMethods
56+
end
57+
end
58+
59+
context "when inputs are valid" do
60+
it "creates a success result" do
61+
[
62+
{ hierarchy_root: nil }
63+
].each { |params| expect(subject.call(params)).to be_success }
64+
end
65+
end
66+
67+
context "when inputs are invalid" do
68+
it "creates a failure result" do
69+
[
70+
{},
71+
{ hierarchy_root: create(:hierarchy_item) },
72+
{ hierarchy_root: "" },
73+
{ hierarchy_root: 42 }
74+
].each { |params| expect(subject.call(params)).to be_failure }
75+
end
76+
end
77+
end
78+
end

0 commit comments

Comments
 (0)