diff --git a/lib/api/v3/root.rb b/lib/api/v3/root.rb index 2524179d0c..4c537e9355 100644 --- a/lib/api/v3/root.rb +++ b/lib/api/v3/root.rb @@ -45,6 +45,7 @@ module API mount ::API::V3::Render::RenderAPI mount ::API::V3::Statuses::StatusesAPI mount ::API::V3::StringObjects::StringObjectsAPI + mount ::API::V3::Types::TypesAPI mount ::API::V3::Users::UsersAPI mount ::API::V3::Versions::VersionsAPI mount ::API::V3::WorkPackages::WorkPackagesAPI diff --git a/lib/api/v3/types/type_collection_representer.rb b/lib/api/v3/types/type_collection_representer.rb new file mode 100644 index 0000000000..45b974ddcd --- /dev/null +++ b/lib/api/v3/types/type_collection_representer.rb @@ -0,0 +1,38 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2015 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. +# +# 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 status 2 +# of the License, or (at your option) any later status. +# +# 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 API + module V3 + module Types + class TypeCollectionRepresenter < ::API::Decorators::Collection + element_decorator ::API::V3::Types::TypeRepresenter + end + end + end +end diff --git a/lib/api/v3/types/type_representer.rb b/lib/api/v3/types/type_representer.rb new file mode 100644 index 0000000000..4cb16b6ba7 --- /dev/null +++ b/lib/api/v3/types/type_representer.rb @@ -0,0 +1,58 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2015 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. +#++ + +module API + module V3 + module Types + class TypeRepresenter < ::API::Decorators::Single + + self_link + + property :id + property :name + property :color, + getter: -> (*) { color.hexcode if color }, + render_nil: true + property :position + property :is_default + property :is_milestone + property :created_at, + exec_context: :decorator, + getter: -> (*) { datetime_formatter.format_datetime(represented.created_at) } + property :updated_at, + exec_context: :decorator, + getter: -> (*) { datetime_formatter.format_datetime(represented.updated_at) } + + def _type + 'Type' + end + end + end + end +end diff --git a/lib/api/v3/types/types_api.rb b/lib/api/v3/types/types_api.rb new file mode 100644 index 0000000000..dcc7be72e3 --- /dev/null +++ b/lib/api/v3/types/types_api.rb @@ -0,0 +1,61 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2015 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. +#++ + +module API + module V3 + module Types + class TypesAPI < Grape::API + resources :types do + before do + authorize(:view_work_packages, global: true) + + @types = Type.all + end + + get do + TypeCollectionRepresenter.new(@types, + @types.count, + api_v3_paths.types) + end + + namespace ':id' do + before do + type = Type.find(params[:id]) + @representer = ::API::V3::Types::TypeRepresenter.new(type) + end + + get do + @representer + end + end + end + end + end + end +end diff --git a/lib/api/v3/utilities/path_helper.rb b/lib/api/v3/utilities/path_helper.rb index 5e7fa437d7..f4236c5bc4 100644 --- a/lib/api/v3/utilities/path_helper.rb +++ b/lib/api/v3/utilities/path_helper.rb @@ -116,6 +116,14 @@ module API "#{root}/string_objects/#{::ERB::Util::url_encode(value)}" end + def self.types + "#{root}/types" + end + + def self.type(id) + "#{types}/#{id}" + end + def self.users "#{root}/users" end diff --git a/spec/lib/api/v3/types/type_representer_spec.rb b/spec/lib/api/v3/types/type_representer_spec.rb new file mode 100644 index 0000000000..703d8f1824 --- /dev/null +++ b/spec/lib/api/v3/types/type_representer_spec.rb @@ -0,0 +1,106 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2015 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' + +describe ::API::V3::Types::TypeRepresenter do + let(:type) { FactoryGirl.build_stubbed(:type, color: FactoryGirl.build(:color)) } + let(:representer) { described_class.new(type) } + + include API::V3::Utilities::PathHelper + + context 'generation' do + subject { representer.to_json } + + describe 'links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } + let(:href) { api_v3_paths.type(type.id) } + let(:title) { type.name } + end + end + + it 'indicates its id' do + is_expected.to be_json_eql(type.id.to_json).at_path('id') + end + + it 'indicates its name' do + is_expected.to be_json_eql(type.name.to_json).at_path('name') + end + + it 'indicates its color' do + is_expected.to be_json_eql(type.color.hexcode.to_json).at_path('color') + end + + context 'no color set' do + let(:type) { FactoryGirl.build(:type, color: nil) } + + it 'indicates a missing color' do + is_expected.to be_json_eql(nil.to_json).at_path('color') + end + end + + it 'indicates its position' do + is_expected.to be_json_eql(type.position.to_json).at_path('position') + end + + it 'indicates that it is not the default type' do + is_expected.to be_json_eql(false.to_json).at_path('isDefault') + end + + context 'as default type' do + let(:type) { FactoryGirl.build(:type, is_default: true) } + + it 'indicates that it is the default type' do + is_expected.to be_json_eql(true.to_json).at_path('isDefault') + end + end + + it 'indicates that it is not a milestone' do + is_expected.to be_json_eql(false.to_json).at_path('isMilestone') + end + + context 'as milestone' do + let(:type) { FactoryGirl.build(:type, is_milestone: true) } + + it 'indicates that it is a milestone' do + is_expected.to be_json_eql(true.to_json).at_path('isMilestone') + end + end + + it_behaves_like 'has UTC ISO 8601 date and time' do + let(:date) { type.created_at } + let(:json_path) { 'createdAt' } + end + + it_behaves_like 'has UTC ISO 8601 date and time' do + let(:date) { type.updated_at } + let(:json_path) { 'updatedAt' } + end + end +end diff --git a/spec/lib/api/v3/utilities/path_helper_spec.rb b/spec/lib/api/v3/utilities/path_helper_spec.rb index bf0955689f..4d4bbcf0cc 100644 --- a/spec/lib/api/v3/utilities/path_helper_spec.rb +++ b/spec/lib/api/v3/utilities/path_helper_spec.rb @@ -254,6 +254,24 @@ describe ::API::V3::Utilities::PathHelper do end end + describe 'types paths' do + describe '#types' do + subject { helper.types } + + it_behaves_like 'api v3 path' + + it { is_expected.to eql('/api/v3/types') } + end + + describe '#type' do + subject { helper.type 1 } + + it_behaves_like 'api v3 path' + + it { is_expected.to eql('/api/v3/types/1') } + end + end + describe '#user' do subject { helper.user 1 } diff --git a/spec/requests/api/v3/type_resource_spec.rb b/spec/requests/api/v3/type_resource_spec.rb new file mode 100644 index 0000000000..2797bfad49 --- /dev/null +++ b/spec/requests/api/v3/type_resource_spec.rb @@ -0,0 +1,113 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2015 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 Type resource' do + include Rack::Test::Methods + + let(:role) { FactoryGirl.create(:role, permissions: [:view_work_packages]) } + let(:project) { FactoryGirl.create(:project, no_types: true, is_public: false) } + let(:current_user) do + FactoryGirl.create(:user, + member_in_project: project, + member_through_role: role) + end + + let!(:types) { FactoryGirl.create_list(:type, 4) } + + describe 'types' do + describe '#get' do + let(:get_path) { '/api/v3/types' } + subject(:response) { last_response } + + context 'logged in user' do + before do + allow(User).to receive(:current).and_return current_user + + get get_path + end + + it_behaves_like 'API V3 collection response', 4, 4, 'Type' + end + + context 'not logged in user' do + before do + get get_path + end + + it_behaves_like 'error response', + 403, + 'MissingPermission', + I18n.t('api_v3.errors.code_403') + end + end + end + + describe 'types/:id' do + describe '#get' do + let(:status) { types.first } + let(:get_path) { "/api/v3/types/#{status.id}" } + + subject(:response) { last_response } + + context 'logged in user' do + before do + allow(User).to receive(:current).and_return(current_user) + + get get_path + end + + context 'valid type id' do + it { expect(response.status).to eq(200) } + end + + context 'invalid type id' do + let(:get_path) { '/api/v3/types/bogus' } + + it_behaves_like 'not found' do + let(:id) { 'bogus' } + let(:type) { 'Type' } + end + end + end + + context 'not logged in user' do + before do + get get_path + end + + it_behaves_like 'error response', + 403, + 'MissingPermission', + I18n.t('api_v3.errors.code_403') + end + end + end +end