use default end points for most of the relations api

pull/7933/head
ulferts 5 years ago
parent 1b7d66bea7
commit 481fe5b291
No known key found for this signature in database
GPG Key ID: A205708DE1284017
  1. 37
      app/contracts/relations/delete_contract.rb
  2. 34
      app/services/relations/base_service.rb
  3. 29
      app/services/relations/delete_service.rb
  4. 12
      app/services/relations/update_service.rb
  5. 30
      lib/api/v3/relations/relations_api.rb
  6. 19
      lib/api/v3/relations/relations_helper.rb
  7. 38
      spec/requests/api/v3/relations/relations_api_spec.rb
  8. 2
      spec/services/relations/update_service_spec.rb

@ -0,0 +1,37 @@
#-- 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 Relations
class DeleteContract < ::DeleteContract
delete_permission -> {
user.allowed_to? :manage_work_package_relations, model.from.project
}
end
end

@ -40,33 +40,33 @@ class Relations::BaseService
private
def update_relation(relation, attributes)
relation.attributes = relation.attributes.merge attributes
def update_relation(model, attributes)
model.attributes = model.attributes.merge attributes
success, errors = validate_and_save(relation, user)
success, errors = retry_with_inverse_for_relates(relation, errors) unless success
success, errors = validate_and_save(model, user)
success, errors = retry_with_inverse_for_relates(model, errors) unless success
result = ServiceResult.new success: success, errors: errors, result: relation
result = ServiceResult.new success: success, errors: errors, result: model
if success && relation.follows?
reschedule_result = reschedule(relation)
if success && model.follows?
reschedule_result = reschedule(model)
result.merge!(reschedule_result)
end
result
end
def set_defaults(relation)
if Relation::TYPE_FOLLOWS == relation.relation_type
relation.delay ||= 0
def set_defaults(model)
if Relation::TYPE_FOLLOWS == model.relation_type
model.delay ||= 0
else
relation.delay = nil
model.delay = nil
end
end
def reschedule(relation)
def reschedule(model)
schedule_result = WorkPackages::SetScheduleService
.new(user: user, work_package: relation.to)
.new(user: user, work_package: model.to)
.call
# The to-work_package will not be altered by the schedule service so
@ -80,12 +80,12 @@ class Relations::BaseService
schedule_result
end
def retry_with_inverse_for_relates(relation, errors)
def retry_with_inverse_for_relates(model, errors)
if errors.symbols_for(:base).include?(:"typed_dag.circular_dependency") &&
relation.canonical_type == Relation::TYPE_RELATES
relation.from, relation.to = relation.to, relation.from
model.canonical_type == Relation::TYPE_RELATES
model.from, model.to = model.to, model.from
validate_and_save(relation, user)
validate_and_save(model, user)
else
[false, errors]
end

@ -0,0 +1,29 @@
#-- 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.
#++
class Relations::DeleteService < ::BaseServices::Delete; end

@ -29,17 +29,17 @@
#++
class Relations::UpdateService < Relations::BaseService
attr_accessor :relation
attr_accessor :model
def initialize(user:, relation:)
def initialize(user:, model:)
super(user: user)
self.relation = relation
self.model = model
self.contract_class = Relations::UpdateContract
end
def call(attributes: {}, send_notifications: true)
in_context(send_notifications) do
update_relation relation, attributes
def call(attributes)
in_context(attributes[:send_notifications]) do
update_relation model, attributes
end
end
end

@ -36,8 +36,6 @@ module API
module V3
module Relations
class RelationsAPI < ::API::OpenProjectAPI
helpers ::API::V3::Relations::RelationsHelper
resources :relations do
get do
scope = Relation
@ -55,32 +53,8 @@ module API
end
get &::API::V3::Utilities::Endpoints::Show.new(model: Relation).mount
patch do
rep = parse_representer.new Relation.new, current_user: current_user
relation = rep.from_json request.body.read
attributes = filter_attributes relation
service = ::Relations::UpdateService.new relation: @relation,
user: current_user
call = service.call attributes: attributes,
send_notifications: (params[:notify] != 'false')
if call.success?
representer.new call.result, current_user: current_user, embed_links: true
else
fail ::API::Errors::ErrorBase.create_and_merge_errors(call.errors)
end
end
delete do
project_id = project_id_for_relation params[:id]
project = Project.find project_id
authorize :manage_work_package_relations, context: project
Relation.destroy params[:id]
status 204
end
patch &::API::V3::Utilities::Endpoints::Update.new(model: Relation).mount
delete &::API::V3::Utilities::Endpoints::Delete.new(model: Relation).mount
end
end
end

@ -30,14 +30,6 @@ module API
module V3
module Relations
module RelationsHelper
def filter_attributes(relation)
relation
.changes
.map { |k, v| [k, v.last] }
.to_h
.with_indifferent_access
end
def representer
::API::V3::Relations::RelationRepresenter
end
@ -45,17 +37,6 @@ module API
def parse_representer
::API::V3::Relations::RelationPayloadRepresenter
end
def project_id_for_relation(id)
relations = Relation.table_name
work_packages = WorkPackage.table_name
Relation
.joins(:from)
.where("#{relations}.id" => id)
.pluck("#{work_packages}.project_id")
.first
end
end
end
end

@ -369,15 +369,45 @@ describe 'API v3 Relation resource', type: :request, content_type: :json do
end
describe "deleting a relation" do
before do
relation
let(:path) do
api_v3_paths.relation(relation.id)
end
let(:permissions) { %i[view_work_packages manage_work_package_relations] }
let(:role) { FactoryBot.create(:role, permissions: permissions) }
delete api_v3_paths.relation(relation.id)
let(:current_user) do
FactoryBot.create(:user).tap do |user|
FactoryBot.create(:member,
project: to.project,
user: user,
roles: [role])
FactoryBot.create(:member,
project: from.project,
user: user,
roles: [role])
end
end
before do
delete path
end
it "should return 204 and destroy the relation" do
expect(last_response.status).to eq 204
expect(Relation.exists?(relation.id)).to eq false
expect(Relation.exists?(relation.id)).to be_falsey
end
context 'lacking the permission' do
let(:permissions) { %i[view_work_packages] }
it 'returns 403' do
expect(last_response.status).to eq 403
end
it 'leaves the relation' do
expect(Relation.exists?(relation.id)).to be_truthy
end
end
end

@ -50,7 +50,7 @@ describe Relations::UpdateService do
start_date: work_package2_start_date)
end
let(:instance) do
described_class.new(user: user, relation: relation)
described_class.new(user: user, model: relation)
end
let(:relation) do
relation = FactoryBot.build_stubbed(:relation)

Loading…
Cancel
Save