Merge pull request #2231 from opf/fix/17403_implement_collection_specification

17403 implement collection specification
pull/2242/head
ulferts 10 years ago
commit 8c9cfd3383
  1. 25
      lib/api/decorators/collection.rb
  2. 4
      lib/api/v3/categories/categories_api.rb
  3. 26
      lib/api/v3/categories/category_collection_representer.rb
  4. 4
      lib/api/v3/priorities/priorities_api.rb
  5. 19
      lib/api/v3/priorities/priority_collection_representer.rb
  6. 19
      lib/api/v3/statuses/status_collection_representer.rb
  7. 4
      lib/api/v3/statuses/statuses_api.rb
  8. 6
      lib/api/v3/users/user_collection_representer.rb
  9. 26
      lib/api/v3/versions/version_collection_representer.rb
  10. 4
      lib/api/v3/versions/versions_api.rb
  11. 13
      lib/api/v3/work_packages/work_packages_api.rb
  12. 27
      spec/lib/api/v3/categories/category_collection_representer_spec.rb
  13. 17
      spec/lib/api/v3/priorities/priority_collection_representer_spec.rb
  14. 21
      spec/lib/api/v3/statuses/shared/status_collection_representer.rb
  15. 8
      spec/lib/api/v3/statuses/status_collection_representer_spec.rb
  16. 42
      spec/lib/api/v3/support/api_v3_collection.rb
  17. 27
      spec/lib/api/v3/users/user_collection_representer_spec.rb
  18. 28
      spec/lib/api/v3/versions/version_collection_representer_spec.rb
  19. 9
      spec/requests/api/v3/category_resource_spec.rb
  20. 10
      spec/requests/api/v3/priority_resource_spec.rb
  21. 10
      spec/requests/api/v3/status_resource_spec.rb
  22. 37
      spec/requests/api/v3/support/api_v3_collection_response.rb
  23. 37
      spec/requests/api/v3/version_resource_spec.rb
  24. 26
      spec/requests/api/v3/work_packages/available_assignees_api_spec.rb
  25. 23
      spec/requests/api/v3/work_packages/available_responsibles_api_spec.rb
  26. 98
      spec/requests/api/v3/work_packages/available_statuses_endpoint_spec.rb

@ -35,23 +35,30 @@ module API
class Collection < Roar::Decorator class Collection < Roar::Decorator
include Roar::JSON::HAL include Roar::JSON::HAL
include Roar::Hypermedia include Roar::Hypermedia
include OpenProject::StaticRouting::UrlHelpers include API::Utilities::UrlHelper
attr_reader :current_user, :as def initialize(models, total, self_link, decorator)
@total = total
@self_link = self_link
@decorator = decorator
def initialize(models, current_user: nil, as: nil)
@current_user = current_user
@as = as.to_s.camelize(:lower)
super(models) super(models)
end end
as_strategy = API::Utilities::CamelCasingStrategy.new as_strategy = API::Utilities::CamelCasingStrategy.new
property :total, as: :_total, exec_context: :decorator link :self do
{ href: "#{root_path}api/v3/#{@self_link}" }
def total
represented.empty? ? 0 : represented.first.class.count
end end
property :_type, getter: -> (*) { 'Collection' }
property :total, getter: -> (*) { @total }, exec_context: :decorator
property :count, getter: -> (*) { empty? ? 0 : count }
collection :elements,
getter: -> (*) { represented.map { |model| @decorator.new(model) } },
exec_context: :decorator,
embedded: true
end end
end end
end end

@ -37,7 +37,9 @@ module API
end end
get do get do
CategoryCollectionRepresenter.new(@categories, project: @project) CategoryCollectionRepresenter.new(@categories,
@categories.count,
"projects/#{@project.identifier}/categories")
end end
end end
end end

@ -34,29 +34,9 @@ require 'roar/json/hal'
module API module API
module V3 module V3
module Categories module Categories
class CategoryCollectionRepresenter < Roar::Decorator class CategoryCollectionRepresenter < ::API::Decorators::Collection
include Roar::JSON::HAL def initialize(models, total, self_link)
include OpenProject::StaticRouting::UrlHelpers super(models, total, self_link, ::API::V3::Categories::CategoryRepresenter)
self.as_strategy = API::Utilities::CamelCasingStrategy.new
attr_reader :project
def initialize(model, project:)
@project = project
super(model)
end
link :self do
"#{root_path}api/v3/projects/#{project.id}/categories"
end
property :_type, exec_context: :decorator
collection :categories, embedded: true, extend: CategoryRepresenter, getter: ->(_) { self }
def _type
'Categories'
end end
end end
end end

@ -37,7 +37,9 @@ module API
end end
get do get do
PriorityCollectionRepresenter.new(@priorities) PriorityCollectionRepresenter.new(@priorities,
@priorities.count,
'priorities')
end end
end end
end end

@ -34,22 +34,9 @@ require 'roar/json/hal'
module API module API
module V3 module V3
module Priorities module Priorities
class PriorityCollectionRepresenter < Roar::Decorator class PriorityCollectionRepresenter < ::API::Decorators::Collection
include Roar::JSON::HAL def initialize(models, total, self_link)
include OpenProject::StaticRouting::UrlHelpers super(models, total, self_link, ::API::V3::Priorities::PriorityRepresenter)
self.as_strategy = API::Utilities::CamelCasingStrategy.new
link :self do
"#{root_path}api/v3/priorities"
end
property :_type, exec_context: :decorator
collection :priorities, embedded: true, extend: PriorityRepresenter, getter: ->(_) { self }
def _type
'Priorities'
end end
end end
end end

@ -34,22 +34,9 @@ require 'roar/json/hal'
module API module API
module V3 module V3
module Statuses module Statuses
class StatusCollectionRepresenter < Roar::Decorator class StatusCollectionRepresenter < ::API::Decorators::Collection
include Roar::JSON::HAL def initialize(models, total, self_link)
include OpenProject::StaticRouting::UrlHelpers super(models, total, self_link, ::API::V3::Statuses::StatusRepresenter)
self.as_strategy = API::Utilities::CamelCasingStrategy.new
link :self do
"#{root_path}api/v3/statuses"
end
property :_type, exec_context: :decorator
collection :statuses, embedded: true, extend: StatusRepresenter, getter: ->(_) { self }
def _type
'Statuses'
end end
end end
end end

@ -37,7 +37,9 @@ module API
end end
get do get do
StatusCollectionRepresenter.new(@statuses) StatusCollectionRepresenter.new(@statuses,
@statuses.count,
'statuses')
end end
namespace ':id' do namespace ':id' do

@ -31,10 +31,8 @@ module API
module V3 module V3
module Users module Users
class UserCollectionRepresenter < ::API::Decorators::Collection class UserCollectionRepresenter < ::API::Decorators::Collection
collection :users, as: -> (*) { as || :users }, exec_context: :decorator, embedded: true def initialize(models, total, self_link)
super(models, total, self_link, ::API::V3::Users::UserRepresenter)
def users
represented.map { |model| ::API::V3::Users::UserRepresenter.new(model) }
end end
end end
end end

@ -34,29 +34,9 @@ require 'roar/json/hal'
module API module API
module V3 module V3
module Versions module Versions
class VersionCollectionRepresenter < Roar::Decorator class VersionCollectionRepresenter < ::API::Decorators::Collection
include Roar::JSON::HAL def initialize(models, total, self_link)
include OpenProject::StaticRouting::UrlHelpers super(models, total, self_link, ::API::V3::Versions::VersionRepresenter)
self.as_strategy = API::Utilities::CamelCasingStrategy.new
attr_reader :project
def initialize(model, project:)
@project = project
super(model)
end
link :self do
"#{root_path}api/v3/projects/#{project.id}/versions"
end
property :_type, exec_context: :decorator
collection :versions, embedded: true, extend: VersionRepresenter, getter: ->(_) { self }
def _type
'Versions'
end end
end end
end end

@ -37,7 +37,9 @@ module API
end end
get do get do
VersionCollectionRepresenter.new(@versions, project: @project) VersionCollectionRepresenter.new(@versions,
@versions.count,
"projects/#{@project.identifier}/versions")
end end
end end
end end

@ -133,7 +133,11 @@ module API
|| authorize(:edit_work_packages, context: @work_package.project) || authorize(:edit_work_packages, context: @work_package.project)
available_assignees = @work_package.assignable_assignees available_assignees = @work_package.assignable_assignees
::API::V3::Users::UserCollectionRepresenter.new(available_assignees, as: :available_assignees) total = available_assignees.count
self_link = "work_packages/#{@work_package.id}/available_assignees"
::API::V3::Users::UserCollectionRepresenter.new(available_assignees,
total,
self_link)
end end
end end
@ -145,13 +149,16 @@ module API
|| authorize(:edit_work_packages, context: @work_package.project) || authorize(:edit_work_packages, context: @work_package.project)
available_responsibles = @work_package.assignable_responsibles available_responsibles = @work_package.assignable_responsibles
::API::V3::Users::UserCollectionRepresenter.new(available_responsibles, as: :available_responsibles) total = available_responsibles.count
self_link = "work_packages/#{@work_package.id}/available_responsibles"
::API::V3::Users::UserCollectionRepresenter.new(available_responsibles,
total,
self_link)
end end
end end
mount ::API::V3::WorkPackages::WatchersAPI mount ::API::V3::WorkPackages::WatchersAPI
mount ::API::V3::WorkPackages::StatusesAPI
mount ::API::V3::Relations::RelationsAPI mount ::API::V3::Relations::RelationsAPI
mount ::API::V3::WorkPackages::Form::FormAPI mount ::API::V3::WorkPackages::Form::FormAPI

@ -29,33 +29,12 @@
require 'spec_helper' require 'spec_helper'
describe ::API::V3::Categories::CategoryCollectionRepresenter do describe ::API::V3::Categories::CategoryCollectionRepresenter do
let(:project) { FactoryGirl.build(:project, id: 888) }
let(:categories) { FactoryGirl.build_list(:category, 3) } let(:categories) { FactoryGirl.build_list(:category, 3) }
let(:representer) { described_class.new(categories, project: project) } let(:representer) { described_class.new(categories, 42, 'projects/1/categories') }
describe '#initialize' do
context 'with incorrect parameters' do
it 'should raise without a project' do
expect { described_class.new(categories) }.to raise_error(ArgumentError)
end
end
end
context 'generation' do context 'generation' do
subject(:generated) { representer.to_json } subject(:collection) { representer.to_json }
it { should include_json('Categories'.to_json).at_path('_type') }
it { should have_json_type(Object).at_path('_links') }
it 'should link to self' do
expect(generated).to have_json_path('_links/self/href')
expect(parse_json(generated, '_links/self/href')).to match %r{/api/v3/projects/888/categories$}
end
describe 'categories' do it_behaves_like 'API V3 collection decorated', 42, 3, 'projects/1/categories', 'Category'
it { should have_json_path('_embedded/categories') }
it { should have_json_size(3).at_path('_embedded/categories') }
it { should have_json_path('_embedded/categories/2/name') }
end
end end
end end

@ -30,22 +30,11 @@ require 'spec_helper'
describe ::API::V3::Priorities::PriorityCollectionRepresenter do describe ::API::V3::Priorities::PriorityCollectionRepresenter do
let(:priorities) { FactoryGirl.build_list(:priority, 3) } let(:priorities) { FactoryGirl.build_list(:priority, 3) }
let(:representer) { described_class.new(priorities) } let(:representer) { described_class.new(priorities, 42, 'priorities') }
context 'generation' do context 'generation' do
subject(:generated) { representer.to_json } subject(:collection) { representer.to_json }
it { should include_json('Priorities'.to_json).at_path('_type') } it_behaves_like 'API V3 collection decorated', 42, 3, 'priorities', 'Priority'
it { should have_json_type(Object).at_path('_links') }
it 'should link to self' do
expect(subject).to have_json_path('_links/self/href')
end
describe 'priorities' do
it { should have_json_path('_embedded/priorities') }
it { should have_json_size(3).at_path('_embedded/priorities') }
it { should have_json_path('_embedded/priorities/2/name') }
end
end end
end end

@ -1,21 +1,4 @@
RSpec.shared_examples 'status collection representer' do RSpec.shared_context 'status collection representer' do |self_link|
let(:statuses) { FactoryGirl.build_list(:status, 3) } let(:statuses) { FactoryGirl.build_list(:status, 3) }
let(:representer) { described_class.new(statuses) } let(:representer) { described_class.new(statuses, 42, self_link) }
context 'generation' do
subject(:generated) { representer.to_json }
it { should include_json('Statuses'.to_json).at_path('_type') }
it { should have_json_type(Object).at_path('_links') }
it 'should link to self' do
expect(subject).to have_json_path('_links/self/href')
end
describe 'statuses' do
it { should have_json_path('_embedded/statuses') }
it { should have_json_size(3).at_path('_embedded/statuses') }
it { should have_json_path('_embedded/statuses/2/name') }
end
end
end end

@ -30,13 +30,11 @@ require 'spec_helper'
require 'lib/api/v3/statuses/shared/status_collection_representer' require 'lib/api/v3/statuses/shared/status_collection_representer'
describe ::API::V3::Statuses::StatusCollectionRepresenter do describe ::API::V3::Statuses::StatusCollectionRepresenter do
include_examples 'status collection representer' include_context 'status collection representer', 'statuses'
context 'generation' do context 'generation' do
subject(:generated) { representer.to_json } subject(:collection) { representer.to_json }
it 'should have link to self' do it_behaves_like 'API V3 collection decorated', 42, 3, 'statuses', 'Status'
expect(parse_json(subject)['_links']['self']['href']).to match(%r{api/v3/statuses$})
end
end end
end end

@ -1,4 +1,3 @@
#-- encoding: UTF-8
#-- copyright #-- copyright
# OpenProject is a project management system. # OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) # Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
@ -27,39 +26,26 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
module API require 'spec_helper'
module V3
module WorkPackages
class StatusesAPI < Grape::API
class AvailableStatusesFormatter
# this is an ugly hack to get the work package id for the path to self
def work_package_id(env)
env['rack.routing_args'][:id]
end
def call(object, env) shared_examples_for 'API V3 collection decorated' do |total, count, self_link, type|
if object.respond_to?(:to_json) it { expect(collection).to be_json_eql('Collection'.to_json).at_path('_type') }
object.to_json(work_package_id: work_package_id(env))
else
MultiJson.dump(object)
end
end
end
formatter 'hal+json', AvailableStatusesFormatter.new describe 'elements' do
it { expect(collection).to be_json_eql(type.to_json).at_path('_embedded/elements/0/_type') }
end
get '/available_statuses' do describe 'quantities' do
authorize({ controller: :work_packages, action: :update }, context: work_package.project) it { expect(collection).to be_json_eql(total.to_json).at_path('total') }
work_package.type = work_package.project.types.find_by_name(params[:type]) if params[:type] it { expect(collection).to be_json_eql(count.to_json).at_path('count') }
statuses = work_package.new_statuses_allowed_to(current_user) it { expect(collection).to have_json_size(count).at_path('_embedded/elements') }
end
represented = ::API::V3::WorkPackages::AvailableStatusCollectionRepresenter.new(statuses) describe '_links' do
let(:href) { "/api/v3/#{self_link}".to_json }
represented it { expect(collection).to be_json_eql(href).at_path('_links/self/href') }
end
end
end
end end
end end

@ -3,7 +3,7 @@
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) # Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License status 3. # 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: # OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang # Copyright (C) 2006-2013 Jean-Philippe Lang
@ -11,8 +11,8 @@
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either status 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later status. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -27,20 +27,19 @@
#++ #++
require 'spec_helper' require 'spec_helper'
require 'lib/api/v3/statuses/shared/status_collection_representer'
describe ::API::V3::WorkPackages::AvailableStatusCollectionRepresenter do describe ::API::V3::Users::UserCollectionRepresenter do
include_examples 'status collection representer' let(:users) {
FactoryGirl.build_list(:user,
3,
created_on: Time.now,
updated_on: Time.now)
}
let(:representer) { described_class.new(users, 42, 'work_package/1/watchers') }
context 'generation' do context 'generation' do
subject(:generated) { representer.to_json(work_package_id: 1) } subject(:collection) { representer.to_json }
it 'should have link to self' do it_behaves_like 'API V3 collection decorated', 42, 3, 'work_package/1/watchers', 'User'
expect(parse_json(subject, '_links/self/href')).to end_with('api/v3/work_packages/1/available_statuses')
end
it 'should have link to work_package' do
expect(parse_json(subject, '_links/work_package/href')).to end_with('api/v3/work_packages/1')
end
end end
end end

@ -29,33 +29,13 @@
require 'spec_helper' require 'spec_helper'
describe ::API::V3::Versions::VersionCollectionRepresenter do describe ::API::V3::Versions::VersionCollectionRepresenter do
let(:project) { FactoryGirl.build(:project, id: 666) } let(:self_link) { 'projects/1/versions' }
let(:versions) { FactoryGirl.build_list(:version, 3) } let(:versions) { FactoryGirl.build_list(:version, 3) }
let(:representer) { described_class.new(versions, project: project) } let(:representer) { described_class.new(versions, 42, self_link) }
describe '#initialize' do
context 'with incorrect parameters' do
it 'should raise without a project' do
expect { described_class.new(versions) }.to raise_error(ArgumentError)
end
end
end
context 'generation' do context 'generation' do
subject(:generated) { representer.to_json } subject(:collection) { representer.to_json }
it { should include_json('Versions'.to_json).at_path('_type') }
it { should have_json_type(Object).at_path('_links') }
it 'should link to self' do
expect(generated).to have_json_path('_links/self/href')
expect(parse_json(generated, '_links/self/href')).to match %r{/api/v3/projects/666/versions$}
end
describe 'versions' do it_behaves_like 'API V3 collection decorated', 42, 3, 'projects/1/versions', 'Version'
it { should have_json_path('_embedded/versions') }
it { should have_json_size(3).at_path('_embedded/versions') }
it { should have_json_path('_embedded/versions/2/name') }
end
end end
end end

@ -55,14 +55,7 @@ describe 'API v3 Category resource' do
get get_path get get_path
end end
it 'should respond with 200' do it_behaves_like 'API V3 collection response', 3, 3, 'Category'
expect(subject.status).to eq(200)
end
it 'should respond with categories' do
expect(subject.body).to include_json('Categories'.to_json).at_path('_type')
expect(subject.body).to have_json_size(3).at_path('_embedded/categories')
end
end end
end end
end end

@ -1,4 +1,3 @@
#-- encoding: UTF-8
#-- copyright #-- copyright
# OpenProject is a project management system. # OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) # Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
@ -54,14 +53,7 @@ describe 'API v3 Priority resource' do
get get_path get get_path
end end
it 'should respond with 200' do it_behaves_like 'API V3 collection response', 2, 2, 'Priority'
expect(subject.status).to eq(200)
end
it 'should respond with priorities, scoped to project' do
expect(subject.body).to include_json('Priorities'.to_json).at_path('_type')
expect(subject.body).to have_json_size(2).at_path('_embedded/priorities')
end
end end
end end
end end

@ -1,4 +1,3 @@
#-- encoding: UTF-8
#-- copyright #-- copyright
# OpenProject is a project management system. # OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) # Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
@ -55,14 +54,7 @@ describe 'API v3 Status resource' do
get get_path get get_path
end end
it 'should respond with 200' do it_behaves_like 'API V3 collection response', 4, 4, 'Status'
expect(subject.status).to eq(200)
end
it 'should respond with statuses, scoped to project' do
expect(subject.body).to include_json('Statuses'.to_json).at_path('_type')
expect(subject.body).to have_json_size(4).at_path('_embedded/statuses')
end
end end
end end
end end

@ -1,10 +1,9 @@
#-- encoding: UTF-8
#-- copyright #-- copyright
# OpenProject is a project management system. # OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) # Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License status 3. # 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: # OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang # Copyright (C) 2006-2013 Jean-Philippe Lang
@ -12,8 +11,8 @@
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either status 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later status. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -27,24 +26,24 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
module API require 'spec_helper'
module V3
module WorkPackages
class AvailableStatusCollectionRepresenter < ::API::V3::Statuses::StatusCollectionRepresenter
link :self do |opts|
"#{work_package_url(opts[:work_package_id])}/available_statuses"
end
link :work_package do |opts| shared_examples_for 'API V3 collection response' do |total, count, type|
work_package_url(opts[:work_package_id]) subject { response.body }
end
private it { expect(response.status).to eql(200) }
def work_package_url(work_package_id) it { is_expected.to be_json_eql('Collection'.to_json).at_path('_type') }
"#{root_path}api/v3/work_packages/#{work_package_id}"
end it { is_expected.to be_json_eql(count.to_json).at_path('count') }
end
it { is_expected.to be_json_eql(total.to_json).at_path('total') }
it { is_expected.to have_json_size(count) .at_path('_embedded/elements') }
it 'has element of specified type if elements exist' do
if count > 0
is_expected.to be_json_eql(type.to_json).at_path('_embedded/elements/0/_type')
end end
end end
end end

@ -1,3 +1,31 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 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-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 doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper' require 'spec_helper'
require 'rack/test' require 'rack/test'
@ -27,14 +55,7 @@ describe 'API v3 Version resource' do
get get_path get get_path
end end
it 'should respond with 200' do it_behaves_like 'API V3 collection response', 4, 4, 'Version'
expect(subject.status).to eq(200)
end
it 'should respond with versions, scoped to project' do
expect(subject.body).to include_json('Versions'.to_json).at_path('_type')
expect(subject.body).to have_json_size(4).at_path('_embedded/versions')
end
end end
end end
end end

@ -48,16 +48,10 @@ describe API::V3::WorkPackages::WorkPackagesAPI, type: :request do
describe 'response' do describe 'response' do
before { allow(User).to receive(:current).and_return(admin) } before { allow(User).to receive(:current).and_return(admin) }
shared_examples_for 'returns available assignees' do shared_examples_for 'returns available assignees' do |total, count|
include_context 'request available assignees' include_context 'request available assignees'
subject { JSON.parse(response.body) } it_behaves_like 'API V3 collection response', total, count, 'User'
it { expect(subject).to have_key('_embedded') }
it { expect(subject['_embedded']).to have_key('availableAssignees') }
it { expect(subject['_embedded']['availableAssignees'].count).to eq(available_assignee_count) }
end end
describe 'users' do describe 'users' do
@ -72,9 +66,7 @@ describe API::V3::WorkPackages::WorkPackagesAPI, type: :request do
allow(user).to receive(:updated_on).and_return(user.created_at) allow(user).to receive(:updated_on).and_return(user.created_at)
end end
it_behaves_like 'returns available assignees' do it_behaves_like 'returns available assignees', 1, 1
let(:available_assignee_count) { 1 }
end
end end
context 'multiple users' do context 'multiple users' do
@ -88,9 +80,7 @@ describe API::V3::WorkPackages::WorkPackagesAPI, type: :request do
allow(user2).to receive(:updated_on).and_return(user.created_at) allow(user2).to receive(:updated_on).and_return(user.created_at)
end end
it_behaves_like 'returns available assignees' do it_behaves_like 'returns available assignees', 2, 2
let(:available_assignee_count) { 2 }
end
end end
end end
@ -106,9 +96,7 @@ describe API::V3::WorkPackages::WorkPackagesAPI, type: :request do
work_package.project.add_member! group, FactoryGirl.create(:role) work_package.project.add_member! group, FactoryGirl.create(:role)
end end
it_behaves_like 'returns available assignees' do it_behaves_like 'returns available assignees', 1, 1
let(:available_assignee_count) { 1 }
end
end end
context 'without work_package_group_assignment' do context 'without work_package_group_assignment' do
@ -117,9 +105,7 @@ describe API::V3::WorkPackages::WorkPackagesAPI, type: :request do
work_package.project.add_member! group, FactoryGirl.create(:role) work_package.project.add_member! group, FactoryGirl.create(:role)
end end
it_behaves_like 'returns available assignees' do it_behaves_like 'returns available assignees', 0, 0
let(:available_assignee_count) { 0 }
end
end end
end end
end end

@ -1,3 +1,4 @@
#-- copyright
# OpenProject is a project management system. # OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) # Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
# #
@ -47,16 +48,10 @@ describe API::V3::WorkPackages::WorkPackagesAPI do
describe 'response' do describe 'response' do
before { allow(User).to receive(:current).and_return(admin) } before { allow(User).to receive(:current).and_return(admin) }
shared_examples_for 'returns available responsibles' do shared_examples_for 'returns available responsibles' do |total, count|
include_context 'request available responsibles' include_context 'request available responsibles'
subject { JSON.parse(response.body) } it_behaves_like 'API V3 collection response', total, count, 'User'
it { expect(subject).to have_key('_embedded') }
it { expect(subject['_embedded']).to have_key('availableResponsibles') }
it { expect(subject['_embedded']['availableResponsibles'].count).to eq(available_responsible_count) }
end end
describe 'users' do describe 'users' do
@ -71,9 +66,7 @@ describe API::V3::WorkPackages::WorkPackagesAPI do
allow(user).to receive(:updated_on).and_return(user.created_at) allow(user).to receive(:updated_on).and_return(user.created_at)
end end
it_behaves_like 'returns available responsibles' do it_behaves_like 'returns available responsibles', 1, 1
let(:available_responsible_count) { 1 }
end
end end
context 'multiple users' do context 'multiple users' do
@ -87,9 +80,7 @@ describe API::V3::WorkPackages::WorkPackagesAPI do
allow(user2).to receive(:updated_on).and_return(user.created_at) allow(user2).to receive(:updated_on).and_return(user.created_at)
end end
it_behaves_like 'returns available responsibles' do it_behaves_like 'returns available responsibles', 2, 2
let(:available_responsible_count) { 2 }
end
end end
end end
@ -105,9 +96,7 @@ describe API::V3::WorkPackages::WorkPackagesAPI do
work_package.project.add_member! group, FactoryGirl.create(:role) work_package.project.add_member! group, FactoryGirl.create(:role)
end end
it_behaves_like 'returns available responsibles' do it_behaves_like 'returns available responsibles', 0, 0
let(:available_responsible_count) { 0 }
end
end end
end end
end end

@ -1,98 +0,0 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 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-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 doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
require 'rack/test'
describe API::V3::WorkPackages::StatusesAPI do
include Rack::Test::Methods
def app
API::V3::Root
end
let(:authorized_user) do
FactoryGirl.create(:user, member_in_project: project,
member_through_role: authorized_role)
end
let(:unauthorized_user) do
FactoryGirl.create(:user, member_in_project: project,
member_through_role: unauthorized_role)
end
let(:authorized_role) { FactoryGirl.create(:role, permissions: [:edit_work_packages]) }
let(:unauthorized_role) { FactoryGirl.create(:role, permissions: []) }
let(:project) { FactoryGirl.create(:valid_project, is_public: false) }
let(:work_package) do
FactoryGirl.create(:work_package, project: project)
end
let(:status) do
FactoryGirl.create(:status)
end
describe '#get work_packages/:id/available_statuses' do
let(:get_path) { "/api/v3/work_packages/#{work_package.id}/available_statuses" }
subject(:response) { last_response }
context 'permitted user' do
let(:new_type) { project.types.first }
let(:new_status) { Status.where("id NOT IN (#{work_package.status.id})").first }
before do
allow(User).to receive(:current).and_return authorized_user
FactoryGirl.create(:workflow, old_status: work_package.status,
new_status: new_status,
role: authorized_role,
type_id: new_type.id)
get get_path, type: new_type.name
end
it 'should respond with 200' do
expect(subject.status).to eql(200)
end
it 'should return a json collection of all statuses' do
expect(parse_json(response.body, '_embedded/statuses/0/name')).to eql(new_status.name)
end
end
context 'unauthorized user' do
before do
allow(User).to receive(:current).and_return unauthorized_user
get get_path
end
it 'should respond with 403' do
expect(subject.status).to eql(403)
end
end
end
end
Loading…
Cancel
Save