diff --git a/lib/api/decorators/collection.rb b/lib/api/decorators/collection.rb index 49fb6d9f7e..5c4dcffbfc 100644 --- a/lib/api/decorators/collection.rb +++ b/lib/api/decorators/collection.rb @@ -35,23 +35,30 @@ module API class Collection < Roar::Decorator include Roar::JSON::HAL 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) end as_strategy = API::Utilities::CamelCasingStrategy.new - property :total, as: :_total, exec_context: :decorator - - def total - represented.empty? ? 0 : represented.first.class.count + link :self do + { href: "#{root_path}api/v3/#{@self_link}" } 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 diff --git a/lib/api/v3/categories/categories_api.rb b/lib/api/v3/categories/categories_api.rb index 05426e5b7a..94d6d227f0 100644 --- a/lib/api/v3/categories/categories_api.rb +++ b/lib/api/v3/categories/categories_api.rb @@ -37,7 +37,9 @@ module API end get do - CategoryCollectionRepresenter.new(@categories, project: @project) + CategoryCollectionRepresenter.new(@categories, + @categories.count, + "projects/#{@project.identifier}/categories") end end end diff --git a/lib/api/v3/categories/category_collection_representer.rb b/lib/api/v3/categories/category_collection_representer.rb index 24d1cf74f5..718b736fc9 100644 --- a/lib/api/v3/categories/category_collection_representer.rb +++ b/lib/api/v3/categories/category_collection_representer.rb @@ -34,29 +34,9 @@ require 'roar/json/hal' module API module V3 module Categories - class CategoryCollectionRepresenter < Roar::Decorator - include Roar::JSON::HAL - include OpenProject::StaticRouting::UrlHelpers - - 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' + class CategoryCollectionRepresenter < ::API::Decorators::Collection + def initialize(models, total, self_link) + super(models, total, self_link, ::API::V3::Categories::CategoryRepresenter) end end end diff --git a/lib/api/v3/priorities/priorities_api.rb b/lib/api/v3/priorities/priorities_api.rb index 2d43c64e54..98d9c60238 100644 --- a/lib/api/v3/priorities/priorities_api.rb +++ b/lib/api/v3/priorities/priorities_api.rb @@ -37,7 +37,9 @@ module API end get do - PriorityCollectionRepresenter.new(@priorities) + PriorityCollectionRepresenter.new(@priorities, + @priorities.count, + 'priorities') end end end diff --git a/lib/api/v3/priorities/priority_collection_representer.rb b/lib/api/v3/priorities/priority_collection_representer.rb index 31d4843d05..40387d5df5 100644 --- a/lib/api/v3/priorities/priority_collection_representer.rb +++ b/lib/api/v3/priorities/priority_collection_representer.rb @@ -34,22 +34,9 @@ require 'roar/json/hal' module API module V3 module Priorities - class PriorityCollectionRepresenter < Roar::Decorator - include Roar::JSON::HAL - include OpenProject::StaticRouting::UrlHelpers - - 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' + class PriorityCollectionRepresenter < ::API::Decorators::Collection + def initialize(models, total, self_link) + super(models, total, self_link, ::API::V3::Priorities::PriorityRepresenter) end end end diff --git a/lib/api/v3/statuses/status_collection_representer.rb b/lib/api/v3/statuses/status_collection_representer.rb index 2daa171873..5550d28bbf 100644 --- a/lib/api/v3/statuses/status_collection_representer.rb +++ b/lib/api/v3/statuses/status_collection_representer.rb @@ -34,22 +34,9 @@ require 'roar/json/hal' module API module V3 module Statuses - class StatusCollectionRepresenter < Roar::Decorator - include Roar::JSON::HAL - include OpenProject::StaticRouting::UrlHelpers - - 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' + class StatusCollectionRepresenter < ::API::Decorators::Collection + def initialize(models, total, self_link) + super(models, total, self_link, ::API::V3::Statuses::StatusRepresenter) end end end diff --git a/lib/api/v3/statuses/statuses_api.rb b/lib/api/v3/statuses/statuses_api.rb index dabca0507a..14b802a517 100644 --- a/lib/api/v3/statuses/statuses_api.rb +++ b/lib/api/v3/statuses/statuses_api.rb @@ -37,7 +37,9 @@ module API end get do - StatusCollectionRepresenter.new(@statuses) + StatusCollectionRepresenter.new(@statuses, + @statuses.count, + 'statuses') end namespace ':id' do diff --git a/lib/api/v3/users/user_collection_representer.rb b/lib/api/v3/users/user_collection_representer.rb index 827cee098e..54503b609f 100644 --- a/lib/api/v3/users/user_collection_representer.rb +++ b/lib/api/v3/users/user_collection_representer.rb @@ -31,10 +31,8 @@ module API module V3 module Users class UserCollectionRepresenter < ::API::Decorators::Collection - collection :users, as: -> (*) { as || :users }, exec_context: :decorator, embedded: true - - def users - represented.map { |model| ::API::V3::Users::UserRepresenter.new(model) } + def initialize(models, total, self_link) + super(models, total, self_link, ::API::V3::Users::UserRepresenter) end end end diff --git a/lib/api/v3/versions/version_collection_representer.rb b/lib/api/v3/versions/version_collection_representer.rb index 70997bb8e6..d2ae25e839 100644 --- a/lib/api/v3/versions/version_collection_representer.rb +++ b/lib/api/v3/versions/version_collection_representer.rb @@ -34,29 +34,9 @@ require 'roar/json/hal' module API module V3 module Versions - class VersionCollectionRepresenter < Roar::Decorator - include Roar::JSON::HAL - include OpenProject::StaticRouting::UrlHelpers - - 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' + class VersionCollectionRepresenter < ::API::Decorators::Collection + def initialize(models, total, self_link) + super(models, total, self_link, ::API::V3::Versions::VersionRepresenter) end end end diff --git a/lib/api/v3/versions/versions_api.rb b/lib/api/v3/versions/versions_api.rb index d994b72163..09ce80a324 100644 --- a/lib/api/v3/versions/versions_api.rb +++ b/lib/api/v3/versions/versions_api.rb @@ -37,7 +37,9 @@ module API end get do - VersionCollectionRepresenter.new(@versions, project: @project) + VersionCollectionRepresenter.new(@versions, + @versions.count, + "projects/#{@project.identifier}/versions") end end end diff --git a/lib/api/v3/work_packages/work_packages_api.rb b/lib/api/v3/work_packages/work_packages_api.rb index 6a221e6529..b6343d3c35 100644 --- a/lib/api/v3/work_packages/work_packages_api.rb +++ b/lib/api/v3/work_packages/work_packages_api.rb @@ -133,7 +133,11 @@ module API || authorize(:edit_work_packages, context: @work_package.project) 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 @@ -145,13 +149,16 @@ module API || authorize(:edit_work_packages, context: @work_package.project) 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 mount ::API::V3::WorkPackages::WatchersAPI - mount ::API::V3::WorkPackages::StatusesAPI mount ::API::V3::Relations::RelationsAPI mount ::API::V3::WorkPackages::Form::FormAPI diff --git a/spec/lib/api/v3/categories/category_collection_representer_spec.rb b/spec/lib/api/v3/categories/category_collection_representer_spec.rb index 8df045c724..2d3587c8b7 100644 --- a/spec/lib/api/v3/categories/category_collection_representer_spec.rb +++ b/spec/lib/api/v3/categories/category_collection_representer_spec.rb @@ -29,33 +29,12 @@ require 'spec_helper' describe ::API::V3::Categories::CategoryCollectionRepresenter do - let(:project) { FactoryGirl.build(:project, id: 888) } let(:categories) { FactoryGirl.build_list(:category, 3) } - let(:representer) { described_class.new(categories, project: project) } - - 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 + let(:representer) { described_class.new(categories, 42, 'projects/1/categories') } context 'generation' do - subject(:generated) { 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 + subject(:collection) { representer.to_json } - describe 'categories' do - 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 + it_behaves_like 'API V3 collection decorated', 42, 3, 'projects/1/categories', 'Category' end end diff --git a/spec/lib/api/v3/priorities/priority_collection_representer_spec.rb b/spec/lib/api/v3/priorities/priority_collection_representer_spec.rb index 990a035f0d..71adbedb94 100644 --- a/spec/lib/api/v3/priorities/priority_collection_representer_spec.rb +++ b/spec/lib/api/v3/priorities/priority_collection_representer_spec.rb @@ -30,22 +30,11 @@ require 'spec_helper' describe ::API::V3::Priorities::PriorityCollectionRepresenter do let(:priorities) { FactoryGirl.build_list(:priority, 3) } - let(:representer) { described_class.new(priorities) } + let(:representer) { described_class.new(priorities, 42, 'priorities') } context 'generation' do - subject(:generated) { representer.to_json } + subject(:collection) { representer.to_json } - it { should include_json('Priorities'.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 '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 + it_behaves_like 'API V3 collection decorated', 42, 3, 'priorities', 'Priority' end end diff --git a/spec/lib/api/v3/statuses/shared/status_collection_representer.rb b/spec/lib/api/v3/statuses/shared/status_collection_representer.rb index 539987bd90..d4a8c84725 100644 --- a/spec/lib/api/v3/statuses/shared/status_collection_representer.rb +++ b/spec/lib/api/v3/statuses/shared/status_collection_representer.rb @@ -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(:representer) { described_class.new(statuses) } - - 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 + let(:representer) { described_class.new(statuses, 42, self_link) } end diff --git a/spec/lib/api/v3/statuses/status_collection_representer_spec.rb b/spec/lib/api/v3/statuses/status_collection_representer_spec.rb index bbbbd959b2..7541c9ed3c 100644 --- a/spec/lib/api/v3/statuses/status_collection_representer_spec.rb +++ b/spec/lib/api/v3/statuses/status_collection_representer_spec.rb @@ -30,13 +30,11 @@ require 'spec_helper' require 'lib/api/v3/statuses/shared/status_collection_representer' describe ::API::V3::Statuses::StatusCollectionRepresenter do - include_examples 'status collection representer' + include_context 'status collection representer', 'statuses' context 'generation' do - subject(:generated) { representer.to_json } + subject(:collection) { representer.to_json } - it 'should have link to self' do - expect(parse_json(subject)['_links']['self']['href']).to match(%r{api/v3/statuses$}) - end + it_behaves_like 'API V3 collection decorated', 42, 3, 'statuses', 'Status' end end diff --git a/lib/api/v3/work_packages/statuses_api.rb b/spec/lib/api/v3/support/api_v3_collection.rb similarity index 53% rename from lib/api/v3/work_packages/statuses_api.rb rename to spec/lib/api/v3/support/api_v3_collection.rb index ed3a998f17..4e028358ab 100644 --- a/lib/api/v3/work_packages/statuses_api.rb +++ b/spec/lib/api/v3/support/api_v3_collection.rb @@ -1,4 +1,3 @@ -#-- encoding: UTF-8 #-- copyright # OpenProject is a project management system. # Copyright (C) 2012-2014 the OpenProject Foundation (OPF) @@ -27,39 +26,26 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -module API - 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 +require 'spec_helper' - def call(object, env) - if object.respond_to?(:to_json) - object.to_json(work_package_id: work_package_id(env)) - else - MultiJson.dump(object) - end - end - end +shared_examples_for 'API V3 collection decorated' do |total, count, self_link, type| + it { expect(collection).to be_json_eql('Collection'.to_json).at_path('_type') } - 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 - authorize({ controller: :work_packages, action: :update }, context: work_package.project) + describe 'quantities' do + 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 - end - end - end + it { expect(collection).to be_json_eql(href).at_path('_links/self/href') } end end diff --git a/spec/lib/api/v3/work_packages/available_status_collection_representer_spec.rb b/spec/lib/api/v3/users/user_collection_representer_spec.rb similarity index 58% rename from spec/lib/api/v3/work_packages/available_status_collection_representer_spec.rb rename to spec/lib/api/v3/users/user_collection_representer_spec.rb index 272e1cd282..9905f8e5ce 100644 --- a/spec/lib/api/v3/work_packages/available_status_collection_representer_spec.rb +++ b/spec/lib/api/v3/users/user_collection_representer_spec.rb @@ -3,7 +3,7 @@ # 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 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: # Copyright (C) 2006-2013 Jean-Philippe Lang @@ -11,8 +11,8 @@ # # 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 status 2 -# of the License, or (at your option) any later status. +# 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 @@ -27,20 +27,19 @@ #++ require 'spec_helper' -require 'lib/api/v3/statuses/shared/status_collection_representer' -describe ::API::V3::WorkPackages::AvailableStatusCollectionRepresenter do - include_examples 'status collection representer' +describe ::API::V3::Users::UserCollectionRepresenter do + 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 - subject(:generated) { representer.to_json(work_package_id: 1) } + subject(:collection) { representer.to_json } - it 'should have link to self' do - 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 + it_behaves_like 'API V3 collection decorated', 42, 3, 'work_package/1/watchers', 'User' end end diff --git a/spec/lib/api/v3/versions/version_collection_representer_spec.rb b/spec/lib/api/v3/versions/version_collection_representer_spec.rb index e2488f4f8b..cf7220caf3 100644 --- a/spec/lib/api/v3/versions/version_collection_representer_spec.rb +++ b/spec/lib/api/v3/versions/version_collection_representer_spec.rb @@ -29,33 +29,13 @@ require 'spec_helper' 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(:representer) { described_class.new(versions, project: project) } - - 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 + let(:representer) { described_class.new(versions, 42, self_link) } context 'generation' do - subject(:generated) { 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 + subject(:collection) { representer.to_json } - describe 'versions' do - 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 + it_behaves_like 'API V3 collection decorated', 42, 3, 'projects/1/versions', 'Version' end end diff --git a/spec/requests/api/v3/category_resource_spec.rb b/spec/requests/api/v3/category_resource_spec.rb index d5a56d66b0..2d49b66c4e 100644 --- a/spec/requests/api/v3/category_resource_spec.rb +++ b/spec/requests/api/v3/category_resource_spec.rb @@ -55,14 +55,7 @@ describe 'API v3 Category resource' do get get_path end - it 'should respond with 200' do - 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 + it_behaves_like 'API V3 collection response', 3, 3, 'Category' end end end diff --git a/spec/requests/api/v3/priority_resource_spec.rb b/spec/requests/api/v3/priority_resource_spec.rb index 41901a8b47..a3678c0a43 100644 --- a/spec/requests/api/v3/priority_resource_spec.rb +++ b/spec/requests/api/v3/priority_resource_spec.rb @@ -1,4 +1,3 @@ -#-- encoding: UTF-8 #-- copyright # OpenProject is a project management system. # Copyright (C) 2012-2014 the OpenProject Foundation (OPF) @@ -54,14 +53,7 @@ describe 'API v3 Priority resource' do get get_path end - it 'should respond with 200' do - 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 + it_behaves_like 'API V3 collection response', 2, 2, 'Priority' end end end diff --git a/spec/requests/api/v3/status_resource_spec.rb b/spec/requests/api/v3/status_resource_spec.rb index 52591f4ba3..ebcd731098 100644 --- a/spec/requests/api/v3/status_resource_spec.rb +++ b/spec/requests/api/v3/status_resource_spec.rb @@ -1,4 +1,3 @@ -#-- encoding: UTF-8 #-- copyright # OpenProject is a project management system. # Copyright (C) 2012-2014 the OpenProject Foundation (OPF) @@ -55,14 +54,7 @@ describe 'API v3 Status resource' do get get_path end - it 'should respond with 200' do - 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 + it_behaves_like 'API V3 collection response', 4, 4, 'Status' end end end diff --git a/lib/api/v3/work_packages/available_status_collection_representer.rb b/spec/requests/api/v3/support/api_v3_collection_response.rb similarity index 55% rename from lib/api/v3/work_packages/available_status_collection_representer.rb rename to spec/requests/api/v3/support/api_v3_collection_response.rb index e0c838b4b5..492f06d6d6 100644 --- a/lib/api/v3/work_packages/available_status_collection_representer.rb +++ b/spec/requests/api/v3/support/api_v3_collection_response.rb @@ -1,10 +1,9 @@ -#-- 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 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: # Copyright (C) 2006-2013 Jean-Philippe Lang @@ -12,8 +11,8 @@ # # 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 status 2 -# of the License, or (at your option) any later status. +# 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 @@ -27,24 +26,24 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -module API - module V3 - module WorkPackages - class AvailableStatusCollectionRepresenter < ::API::V3::Statuses::StatusCollectionRepresenter - link :self do |opts| - "#{work_package_url(opts[:work_package_id])}/available_statuses" - end +require 'spec_helper' - link :work_package do |opts| - work_package_url(opts[:work_package_id]) - end +shared_examples_for 'API V3 collection response' do |total, count, type| + subject { response.body } - private + it { expect(response.status).to eql(200) } - def work_package_url(work_package_id) - "#{root_path}api/v3/work_packages/#{work_package_id}" - end - end + it { is_expected.to be_json_eql('Collection'.to_json).at_path('_type') } + + it { is_expected.to be_json_eql(count.to_json).at_path('count') } + + 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 diff --git a/spec/requests/api/v3/version_resource_spec.rb b/spec/requests/api/v3/version_resource_spec.rb index 54ffa0f96c..c48a693294 100644 --- a/spec/requests/api/v3/version_resource_spec.rb +++ b/spec/requests/api/v3/version_resource_spec.rb @@ -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 'rack/test' @@ -27,14 +55,7 @@ describe 'API v3 Version resource' do get get_path end - it 'should respond with 200' do - 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 + it_behaves_like 'API V3 collection response', 4, 4, 'Version' end end end diff --git a/spec/requests/api/v3/work_packages/available_assignees_api_spec.rb b/spec/requests/api/v3/work_packages/available_assignees_api_spec.rb index 9065166860..55bc3e8d26 100644 --- a/spec/requests/api/v3/work_packages/available_assignees_api_spec.rb +++ b/spec/requests/api/v3/work_packages/available_assignees_api_spec.rb @@ -48,16 +48,10 @@ describe API::V3::WorkPackages::WorkPackagesAPI, type: :request do describe 'response' do 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' - subject { JSON.parse(response.body) } - - 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) } + it_behaves_like 'API V3 collection response', total, count, 'User' end 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) end - it_behaves_like 'returns available assignees' do - let(:available_assignee_count) { 1 } - end + it_behaves_like 'returns available assignees', 1, 1 end 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) end - it_behaves_like 'returns available assignees' do - let(:available_assignee_count) { 2 } - end + it_behaves_like 'returns available assignees', 2, 2 end end @@ -106,9 +96,7 @@ describe API::V3::WorkPackages::WorkPackagesAPI, type: :request do work_package.project.add_member! group, FactoryGirl.create(:role) end - it_behaves_like 'returns available assignees' do - let(:available_assignee_count) { 1 } - end + it_behaves_like 'returns available assignees', 1, 1 end 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) end - it_behaves_like 'returns available assignees' do - let(:available_assignee_count) { 0 } - end + it_behaves_like 'returns available assignees', 0, 0 end end end diff --git a/spec/requests/api/v3/work_packages/available_responsibles_api_spec.rb b/spec/requests/api/v3/work_packages/available_responsibles_api_spec.rb index c936d5f214..746ab27a40 100644 --- a/spec/requests/api/v3/work_packages/available_responsibles_api_spec.rb +++ b/spec/requests/api/v3/work_packages/available_responsibles_api_spec.rb @@ -1,3 +1,4 @@ +#-- copyright # OpenProject is a project management system. # Copyright (C) 2012-2014 the OpenProject Foundation (OPF) # @@ -47,16 +48,10 @@ describe API::V3::WorkPackages::WorkPackagesAPI do describe 'response' do 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' - subject { JSON.parse(response.body) } - - 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) } + it_behaves_like 'API V3 collection response', total, count, 'User' end describe 'users' do @@ -71,9 +66,7 @@ describe API::V3::WorkPackages::WorkPackagesAPI do allow(user).to receive(:updated_on).and_return(user.created_at) end - it_behaves_like 'returns available responsibles' do - let(:available_responsible_count) { 1 } - end + it_behaves_like 'returns available responsibles', 1, 1 end 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) end - it_behaves_like 'returns available responsibles' do - let(:available_responsible_count) { 2 } - end + it_behaves_like 'returns available responsibles', 2, 2 end end @@ -105,9 +96,7 @@ describe API::V3::WorkPackages::WorkPackagesAPI do work_package.project.add_member! group, FactoryGirl.create(:role) end - it_behaves_like 'returns available responsibles' do - let(:available_responsible_count) { 0 } - end + it_behaves_like 'returns available responsibles', 0, 0 end end end diff --git a/spec/requests/api/v3/work_packages/available_statuses_endpoint_spec.rb b/spec/requests/api/v3/work_packages/available_statuses_endpoint_spec.rb deleted file mode 100644 index 3f4272b98c..0000000000 --- a/spec/requests/api/v3/work_packages/available_statuses_endpoint_spec.rb +++ /dev/null @@ -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