diff --git a/modules/bcf/app/contracts/bcf/concerns/manage_bcf_guarded.rb b/modules/bcf/app/contracts/bcf/concerns/manage_bcf_guarded.rb new file mode 100644 index 0000000000..51f5972525 --- /dev/null +++ b/modules/bcf/app/contracts/bcf/concerns/manage_bcf_guarded.rb @@ -0,0 +1,51 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2017 the OpenProject Foundation (OPF) +# +# 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-2017 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 doc/COPYRIGHT.rdoc for more details. +#++ + +module Bcf::Concerns + module ManageBcfGuarded + extend ActiveSupport::Concern + + included do + def validate + validate_user_allowed_to_manage + + super + end + + private + + def validate_user_allowed_to_manage + unless model.project && user.allowed_to?(:manage_bcf, model.project) + errors.add :base, :error_unauthorized + end + end + end + end +end diff --git a/modules/bcf/app/contracts/bcf/issues/base_contract.rb b/modules/bcf/app/contracts/bcf/issues/base_contract.rb index 3be0a0889e..e0c146fa09 100644 --- a/modules/bcf/app/contracts/bcf/issues/base_contract.rb +++ b/modules/bcf/app/contracts/bcf/issues/base_contract.rb @@ -30,20 +30,8 @@ module Bcf::Issues class BaseContract < ::ModelContract - attribute :index - - def validate - validate_user_allowed_to_manage - - super - end + include Bcf::Concerns::ManageBcfGuarded - private - - def validate_user_allowed_to_manage - unless model.project && user.allowed_to?(:manage_bcf, model.project) - errors.add :base, :error_unauthorized - end - end + attribute :index end end diff --git a/modules/bcf/app/contracts/bcf/viewpoints/create_contract.rb b/modules/bcf/app/contracts/bcf/viewpoints/create_contract.rb new file mode 100644 index 0000000000..b101a56190 --- /dev/null +++ b/modules/bcf/app/contracts/bcf/viewpoints/create_contract.rb @@ -0,0 +1,47 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2017 the OpenProject Foundation (OPF) +# +# 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-2017 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 doc/COPYRIGHT.rdoc for more details. +#++ + +module Bcf::Viewpoints + class CreateContract < ::ModelContract + include Bcf::Concerns::ManageBcfGuarded + + attribute :uuid + attribute :issue + attribute :json_viewpoint do + validate_json_viewpoint_present + end + + def validate_json_viewpoint_present + unless model.json_viewpoint.present? + errors.add(:json_viewpoint, :blank) + end + end + end +end diff --git a/modules/bcf/app/controllers/bcf/api/v2_1/viewpoints/api.rb b/modules/bcf/app/controllers/bcf/api/v2_1/viewpoints/api.rb index 9f19781108..ac874e2133 100644 --- a/modules/bcf/app/controllers/bcf/api/v2_1/viewpoints/api.rb +++ b/modules/bcf/app/controllers/bcf/api/v2_1/viewpoints/api.rb @@ -33,11 +33,21 @@ module Bcf::API::V2_1 class API < ::API::OpenProjectAPI resources :viewpoints do get do - @issue.viewpoints - .select(:json_viewpoint) - .map(&:json_viewpoint) + @issue + .viewpoints + .pluck(:json_viewpoint) end + post &::Bcf::API::V2_1::Endpoints::Create + .new(model: Bcf::Viewpoint, + params_modifier: ->(attributes) { + { + json_viewpoint: attributes, + issue: @issue + } + }) + .mount + route_param :viewpoint_uuid, regexp: /\A[a-f0-9\-]+\z/ do %i[/ selection coloring visibility].each do |key| namespace = key == :/ ? :Full : key.to_s.camelize diff --git a/modules/bcf/app/models/bcf/issue.rb b/modules/bcf/app/models/bcf/issue.rb index ba969cb5ad..d8ccb32785 100644 --- a/modules/bcf/app/models/bcf/issue.rb +++ b/modules/bcf/app/models/bcf/issue.rb @@ -7,8 +7,8 @@ module Bcf belongs_to :work_package has_one :project, through: :work_package - has_many :viewpoints, foreign_key: :issue_id, class_name: "Bcf::Viewpoint" - has_many :comments, foreign_key: :issue_id, class_name: "Bcf::Comment" + has_many :viewpoints, foreign_key: :issue_id, class_name: "Bcf::Viewpoint", dependent: :destroy + has_many :comments, foreign_key: :issue_id, class_name: "Bcf::Comment", dependent: :destroy after_update :invalidate_markup_cache diff --git a/modules/bcf/app/models/bcf/viewpoint.rb b/modules/bcf/app/models/bcf/viewpoint.rb index e5d6426deb..76995f053f 100644 --- a/modules/bcf/app/models/bcf/viewpoint.rb +++ b/modules/bcf/app/models/bcf/viewpoint.rb @@ -15,6 +15,8 @@ module Bcf has_many :comments, foreign_key: :viewpoint_id, class_name: "Bcf::Comment" delegate :project, :project_id, to: :issue, allow_nil: true + validates :issue, presence: true + def raw_json_viewpoint attributes_before_type_cast['json_viewpoint'] end diff --git a/modules/bcf/app/representers/bcf/api/v2_1/viewpoints/single_representer.rb b/modules/bcf/app/representers/bcf/api/v2_1/viewpoints/single_representer.rb new file mode 100644 index 0000000000..a20e7c0cb1 --- /dev/null +++ b/modules/bcf/app/representers/bcf/api/v2_1/viewpoints/single_representer.rb @@ -0,0 +1,53 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +module Bcf::API::V2_1 + class Viewpoints::SingleRepresenter < BaseRepresenter + property :lines + + property :bitmaps + + property :snapshot + + property :components + + property :index + + property :orthogonal_camera + + property :perspective_camera + + property :clipping_planes + + def to_json(*) + represented.read_attribute_before_type_cast('json_viewpoint') + end + end +end diff --git a/modules/bcf/app/services/bcf/viewpoints/create_service.rb b/modules/bcf/app/services/bcf/viewpoints/create_service.rb new file mode 100644 index 0000000000..27671724f7 --- /dev/null +++ b/modules/bcf/app/services/bcf/viewpoints/create_service.rb @@ -0,0 +1,34 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2019 the OpenProject Foundation (OPF) +# +# 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-2017 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 doc/COPYRIGHT.rdoc for more details. +#++ + +module Bcf::Viewpoints + class CreateService < ::BaseServices::Create + end +end diff --git a/modules/bcf/app/services/bcf/viewpoints/set_attributes_service.rb b/modules/bcf/app/services/bcf/viewpoints/set_attributes_service.rb new file mode 100644 index 0000000000..6511a95c60 --- /dev/null +++ b/modules/bcf/app/services/bcf/viewpoints/set_attributes_service.rb @@ -0,0 +1,37 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2019 the OpenProject Foundation (OPF) +# +# 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-2017 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 doc/COPYRIGHT.rdoc for more details. +#++ + +module Bcf::Viewpoints + class SetAttributesService < ::BaseServices::SetAttributes + def set_default_attributes(_params) + model.json_viewpoint['guid'] = model.uuid + end + end +end diff --git a/modules/bcf/spec/contracts/bcf/viewpoints/create_contract_spec.rb b/modules/bcf/spec/contracts/bcf/viewpoints/create_contract_spec.rb new file mode 100644 index 0000000000..eb51a6a8e1 --- /dev/null +++ b/modules/bcf/spec/contracts/bcf/viewpoints/create_contract_spec.rb @@ -0,0 +1,106 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe Bcf::Viewpoints::CreateContract do + let(:viewpoint) do + Bcf::Viewpoint.new(uuid: viewpoint_uuid, + issue: viewpoint_issue, + json_viewpoint: viewpoint_json_viewpoint) + end + let(:permissions) { [:manage_bcf] } + + subject(:contract) { described_class.new(viewpoint, current_user) } + + let(:current_user) do + FactoryBot.build_stubbed(:user) + end + let!(:allowed_to) do + allow(current_user) + .to receive(:allowed_to?) do |permission, permission_project| + permissions.include?(permission) && project == permission_project + end + end + let(:viewpoint_uuid) { 'issue uuid' } + let(:viewpoint_json_viewpoint) { 'some json' } + let(:viewpoint_issue) do + FactoryBot.build_stubbed(:bcf_issue).tap do |issue| + allow(issue) + .to receive(:project) + .and_return(project) + end + end + let(:project) { FactoryBot.build_stubbed(:project) } + + def expect_valid(valid, symbols = {}) + expect(contract.validate).to eq(valid) + + symbols.each do |key, arr| + expect(contract.errors.symbols_for(key)).to match_array arr + end + end + + shared_examples 'is valid' do + it 'is valid' do + expect_valid(true) + end + end + + it_behaves_like 'is valid' + + context 'if the uuid is nil' do + let(:issue_uuid) { nil } + + it_behaves_like 'is valid' # as the uuid will be set + end + + context 'if the issue is nil' do + let(:viewpoint_issue) { nil } + + it 'is invalid' do + expect_valid(false, issue: %i(blank)) + end + end + + context 'if the json_viewpoint is nil' do + let(:viewpoint_json_viewpoint) { nil } + + it 'is invalid' do + expect_valid(false, json_viewpoint: %i(blank)) + end + end + + context 'if the user lacks permission' do + let(:permissions) { [] } + + it 'is invalid' do + expect_valid(false, base: %i(error_unauthorized)) + end + end +end diff --git a/modules/bcf/spec/representers/bcf/api/v2_1/viewpoints/single_representer_rendering_spec.rb b/modules/bcf/spec/representers/bcf/api/v2_1/viewpoints/single_representer_rendering_spec.rb new file mode 100644 index 0000000000..e1eae59700 --- /dev/null +++ b/modules/bcf/spec/representers/bcf/api/v2_1/viewpoints/single_representer_rendering_spec.rb @@ -0,0 +1,43 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2019 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +require_relative '../shared_examples' + +describe Bcf::API::V2_1::Viewpoints::SingleRepresenter, 'rendering' do + let(:viewpoint) { FactoryBot.build_stubbed(:bcf_viewpoint) } + let(:instance) { described_class.new(viewpoint) } + + subject { instance.to_json } + + it 'renders only the json_viewpoint attribute (as root)' do + expect(subject) + .to be_json_eql(viewpoint.read_attribute_before_type_cast('json_viewpoint')) + end +end diff --git a/modules/bcf/spec/representers/bcf/api/v2_1/viewpoints/single_representers_parsing_spec.rb b/modules/bcf/spec/representers/bcf/api/v2_1/viewpoints/single_representers_parsing_spec.rb new file mode 100644 index 0000000000..445ec1a1e3 --- /dev/null +++ b/modules/bcf/spec/representers/bcf/api/v2_1/viewpoints/single_representers_parsing_spec.rb @@ -0,0 +1,98 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2017 the OpenProject Foundation (OPF) +# +# 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-2017 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 doc/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe Bcf::API::V2_1::Viewpoints::SingleRepresenter, 'rendering' do + let(:struct) do + OpenStruct.new + end + let(:hash) do + FactoryBot + .attributes_for(:bcf_viewpoint)[:json_viewpoint] + .merge( + "snapshot" => + { + "snapshot_type" => "png", + "snapshot_data" => "SGVsbG8gV29ybGQh" + }, + "index" => 5, + "orthogonal_camera" => + { + "camera_view_point" => { + "x" => 12.2088897788292, + "y" => 52.323145074034, + "z" => 5.24072091171001 + }, + "camera_direction" => { + "x" => -0.381615611200324, + "y" => -0.825232810204882, + "z" => -0.416365617893758 + }, + "camera_up_vector" => { + "x" => 0.05857014928797, + "y" => 0.126656300502579, + "z" => 0.990215996212637 + }, + "field_of_view" => 60.0 + } + ) + end + let(:representer) { described_class.new(struct) } + + subject { representer.from_hash(hash).to_h.to_json } + + shared_examples_for 'parses' do |attribute| + it attribute do + expect(subject) + .to be_json_eql(hash[attribute].to_json) + .at_path(attribute) + end + end + + it 'does not parse uuid' do + expect(subject) + .not_to have_json_path('guid') + end + + it_behaves_like 'parses', 'index' + + it_behaves_like 'parses', 'orthogonal_camera' + + it_behaves_like 'parses', 'perspective_camera' + + it_behaves_like 'parses', 'lines' + + it_behaves_like 'parses', 'clipping_planes' + + it_behaves_like 'parses', 'bitmaps' # in order to throw a not writable error) + + it_behaves_like 'parses', 'snapshot' + + it_behaves_like 'parses', 'components' +end diff --git a/modules/bcf/spec/requests/api/bcf/v2_1/viewpoints_api_spec.rb b/modules/bcf/spec/requests/api/bcf/v2_1/viewpoints_api_spec.rb index d12087c057..e21f3e690c 100644 --- a/modules/bcf/spec/requests/api/bcf/v2_1/viewpoints_api_spec.rb +++ b/modules/bcf/spec/requests/api/bcf/v2_1/viewpoints_api_spec.rb @@ -46,6 +46,12 @@ describe 'BCF 2.1 viewpoints resource', type: :request, content_type: :json, wit member_with_permissions: [:view_linked_issues]) end + shared_let(:create_user) do + FactoryBot.create(:user, + member_in_project: project, + member_with_permissions: %i[view_linked_issues manage_bcf]) + end + shared_let(:non_member_user) do FactoryBot.create(:user) end @@ -164,4 +170,45 @@ describe 'BCF 2.1 viewpoints resource', type: :request, content_type: :json, wit let(:expected_message) { 'Bitmaps are not yet implemented.' } end end + + describe 'POST /api/bcf/2.1/projects/:project_id/topics/:topic/viewpoints' do + let(:path) { "/api/bcf/2.1/projects/#{project.id}/topics/#{bcf_issue.uuid}/viewpoints" } + let(:current_user) { create_user } + let(:params) do + FactoryBot.attributes_for(:bcf_viewpoint)[:json_viewpoint] + end + + before do + login_as(current_user) + post path, params.to_json + end + + it_behaves_like 'bcf api successful response' do + let(:expected_body) do + new_viewpoint = Bcf::Viewpoint.last + + viewpoint_json + .merge(guid: new_viewpoint.uuid) + end + + let(:expected_status) { 201 } + end + + it 'creates the viewpoint' do + expect(Bcf::Viewpoint.count) + .to eql 2 + end + + context 'lacking permission to see project' do + let(:current_user) { non_member_user } + + it_behaves_like 'bcf api not found response' + end + + context 'lacking manage_bcf permission' do + let(:current_user) { view_only_user } + + it_behaves_like 'bcf api not allowed response' + end + end end diff --git a/modules/bcf/spec/services/bcf/viewpoints/create_service_spec.rb b/modules/bcf/spec/services/bcf/viewpoints/create_service_spec.rb new file mode 100644 index 0000000000..4bc5993316 --- /dev/null +++ b/modules/bcf/spec/services/bcf/viewpoints/create_service_spec.rb @@ -0,0 +1,156 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe Bcf::Viewpoints::CreateService, type: :model do + let(:user) { FactoryBot.build_stubbed(:user) } + let(:contract_class) do + double('contract_class', '<=': true) + end + let(:viewpoint_valid) { true } + let(:instance) do + described_class.new(user: user, + contract_class: contract_class) + end + let(:call_attributes) do + { + "snapshot" => + { + "snapshot_type" => "png", + "snapshot_data" => "SGVsbG8gV29ybGQh" + } + } + end + let(:set_attributes_success) do + true + end + let(:set_attributes_errors) do + double('set_attributes_errors') + end + let(:set_attributes_result) do + ServiceResult.new result: created_viewpoint, + success: set_attributes_success, + errors: set_attributes_errors + end + let!(:created_viewpoint) do + viewpoint = FactoryBot.build_stubbed(:bcf_viewpoint) + + allow(Bcf::Viewpoint) + .to receive(:new) + .and_return(viewpoint) + + allow(viewpoint) + .to receive(:save) + .and_return(viewpoint_valid) + + viewpoint + end + let!(:set_attributes_service) do + service = double('set_attributes_service_instance') + + allow(Bcf::Viewpoints::SetAttributesService) + .to receive(:new) + .with(user: user, + model: created_viewpoint, + contract_class: contract_class) + .and_return(service) + + allow(service) + .to receive(:call) + .and_return(set_attributes_result) + end + + describe '#call' do + subject { instance.call(call_attributes) } + + it 'is successful' do + expect(subject.success?).to be_truthy + end + + it 'returns the result of the SetAttributesService' do + expect(subject) + .to eql set_attributes_result + end + + it 'persists the viewpoint' do + expect(created_viewpoint) + .to receive(:save) + .and_return(viewpoint_valid) + + subject + end + + it 'returns a viewpoint' do + expect(subject.result) + .to eql created_viewpoint + end + + context 'if the SetAttributeService is unsuccessful' do + let(:set_attributes_success) { false } + + it 'is unsuccessful' do + expect(subject.success?).to be_falsey + end + + it 'returns the result of the SetAttributesService' do + expect(subject) + .to eql set_attributes_result + end + + it 'does not persist the changes' do + expect(created_viewpoint) + .to_not receive(:save) + + subject + end + + it "exposes the contract's errors" do + subject + + expect(subject.errors).to eql set_attributes_errors + end + end + + context 'when the viewpoint is invalid' do + let(:viewpoint_valid) { false } + + it 'is unsuccessful' do + expect(subject.success?).to be_falsey + end + + it "exposes the viewpoint's errors" do + subject + + expect(subject.errors).to eql created_viewpoint.errors + end + end + end +end diff --git a/modules/bcf/spec/services/bcf/viewpoints/set_attributes_service_spec.rb b/modules/bcf/spec/services/bcf/viewpoints/set_attributes_service_spec.rb new file mode 100644 index 0000000000..ce8c13979d --- /dev/null +++ b/modules/bcf/spec/services/bcf/viewpoints/set_attributes_service_spec.rb @@ -0,0 +1,107 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe Bcf::Viewpoints::SetAttributesService, type: :model do + let(:user) { FactoryBot.build_stubbed(:user) } + let(:contract_class) do + contract = double('contract_class') + + allow(contract) + .to receive(:new) + .with(viewpoint, user, options: { changed_by_system: [] }) + .and_return(contract_instance) + + contract + end + let(:contract_instance) do + double('contract_instance', validate: contract_valid, errors: contract_errors) + end + let(:contract_valid) { true } + let(:contract_errors) do + double('contract_errors') + end + let(:viewpoint_valid) { true } + let(:instance) do + described_class.new(user: user, + model: viewpoint, + contract_class: contract_class) + end + let(:call_attributes) { {} } + let(:viewpoint) do + Bcf::Viewpoint.new + end + + describe 'call' do + # We only expect the service to be called for new records. As viewpoints + # are immutable. + context 'for a new record' do + let(:call_attributes) do + attributes = FactoryBot.attributes_for(:bcf_viewpoint) + attributes[:json_viewpoint].delete('guid') + attributes + end + + before do + allow(viewpoint) + .to receive(:valid?) + .and_return(viewpoint_valid) + + expect(contract_instance) + .to receive(:validate) + .and_return(contract_valid) + end + + subject { instance.call(call_attributes) } + + it 'is successful' do + expect(subject.success?).to be_truthy + end + + it 'sets the attributes with the uuid added to the json_viewpoint' do + subject + + expected_attributes = FactoryBot.attributes_for(:bcf_viewpoint) + expected_attributes[:json_viewpoint]['guid'] = viewpoint.uuid + + expect(viewpoint.attributes.slice(*viewpoint.changed).symbolize_keys) + .to eql expected_attributes + end + + it 'does not persist the viewpoint' do + expect(viewpoint) + .not_to receive(:save) + + subject + end + end + end +end