parent
02e26879ac
commit
aaa7216d80
@ -1,14 +0,0 @@ |
||||
#!/usr/bin/env ruby |
||||
# This command will automatically be run when you run "rails" with Rails gems |
||||
# installed from the root of your application. |
||||
|
||||
ENGINE_ROOT = File.expand_path('../..', __FILE__) |
||||
ENGINE_PATH = File.expand_path('../../lib/grids/engine', __FILE__) |
||||
APP_PATH = File.expand_path('../../test/dummy/config/application', __FILE__) |
||||
|
||||
# Set up gems listed in the Gemfile. |
||||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) |
||||
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) |
||||
|
||||
require 'rails/all' |
||||
require 'rails/engine/commands' |
@ -1,28 +1,4 @@ |
||||
FactoryBot.define do |
||||
factory :grid, class: Grids::Grid do |
||||
end |
||||
|
||||
factory :my_page, class: Grids::MyPage do |
||||
user |
||||
row_count { 7 } |
||||
column_count { 4 } |
||||
widgets do |
||||
[ |
||||
Grids::Widget.new( |
||||
identifier: 'work_packages_assigned', |
||||
start_row: 1, |
||||
end_row: 7, |
||||
start_column: 1, |
||||
end_column: 3 |
||||
), |
||||
Grids::Widget.new( |
||||
identifier: 'work_packages_created', |
||||
start_row: 1, |
||||
end_row: 7, |
||||
start_column: 3, |
||||
end_column: 5 |
||||
) |
||||
] |
||||
end |
||||
end |
||||
end |
||||
|
@ -0,0 +1,7 @@ |
||||
.bundle/ |
||||
log/*.log |
||||
pkg/ |
||||
test/dummy/db/*.sqlite3 |
||||
test/dummy/db/*.sqlite3-journal |
||||
test/dummy/log/*.log |
||||
test/dummy/tmp/ |
@ -0,0 +1,3 @@ |
||||
source 'https://rubygems.org' |
||||
|
||||
gemspec |
@ -0,0 +1,4 @@ |
||||
require "my_page/engine" |
||||
|
||||
module MyPage |
||||
end |
@ -0,0 +1,11 @@ |
||||
module MyPage |
||||
class Engine < ::Rails::Engine |
||||
isolate_namespace MyPage |
||||
|
||||
include OpenProject::Plugins::ActsAsOpEngine |
||||
|
||||
config.to_prepare do |
||||
MyPage::GridRegistration.register! |
||||
end |
||||
end |
||||
end |
@ -1,5 +1,5 @@ |
||||
module Grids |
||||
class MyPageGridRegistration < ::Grids::Configuration::Registration |
||||
module MyPage |
||||
class GridRegistration < ::Grids::Configuration::Registration |
||||
grid_class 'Grids::MyPage' |
||||
to_scope :my_page_path |
||||
|
@ -0,0 +1,12 @@ |
||||
# encoding: UTF-8 |
||||
|
||||
Gem::Specification.new do |s| |
||||
s.name = "my_page" |
||||
s.version = '1.0.0' |
||||
s.authors = ["OpenProject"] |
||||
s.summary = "OpenProject MyPage." |
||||
|
||||
s.files = Dir["{app,config,db,lib}/**/*"] |
||||
|
||||
s.add_dependency 'grids' |
||||
end |
@ -0,0 +1,61 @@ |
||||
#-- 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. |
||||
#++ |
||||
|
||||
require 'spec_helper' |
||||
require_relative './shared_examples' |
||||
|
||||
describe Grids::CreateContract do |
||||
include_context 'grid contract' |
||||
include_context 'model contract' |
||||
|
||||
it_behaves_like 'shared grid contract attributes' |
||||
|
||||
describe 'user_id' do |
||||
context 'for a Grids::MyPage' do |
||||
let(:grid) { FactoryBot.build_stubbed(:my_page, default_values) } |
||||
|
||||
it_behaves_like 'is writable' do |
||||
let(:attribute) { :user_id } |
||||
let(:value) { 5 } |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'project_id' do |
||||
context 'for a Grids::MyPage' do |
||||
let(:grid) { FactoryBot.build_stubbed(:my_page, default_values) } |
||||
|
||||
it_behaves_like 'is not writable' do |
||||
let(:attribute) { :project_id } |
||||
let(:value) { 5 } |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,320 @@ |
||||
#-- 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. |
||||
#++ |
||||
|
||||
shared_context 'grid contract' do |
||||
let(:user) { FactoryBot.build_stubbed(:user) } |
||||
let(:instance) { described_class.new(grid, user) } |
||||
let(:default_values) do |
||||
{ |
||||
row_count: 6, |
||||
column_count: 7, |
||||
widgets: [] |
||||
} |
||||
end |
||||
let(:grid) do |
||||
FactoryBot.build_stubbed(:my_page, default_values) |
||||
end |
||||
end |
||||
|
||||
shared_examples_for 'shared grid contract attributes' do |
||||
include_context 'model contract' |
||||
let(:model) { grid } |
||||
|
||||
describe 'widgets' do |
||||
it_behaves_like 'is writable' do |
||||
let(:attribute) { :widgets } |
||||
let(:value) do |
||||
[ |
||||
Grids::Widget.new(start_row: 1, |
||||
end_row: 4, |
||||
start_column: 2, |
||||
end_column: 5, |
||||
identifier: 'work_packages_assigned') |
||||
] |
||||
end |
||||
end |
||||
|
||||
context 'invalid identifier' do |
||||
before do |
||||
grid.widgets.build(start_row: 1, |
||||
end_row: 4, |
||||
start_column: 2, |
||||
end_column: 5, |
||||
identifier: 'bogus_identifier') |
||||
end |
||||
|
||||
it 'is invalid' do |
||||
expect(instance.validate) |
||||
.to be_falsey |
||||
end |
||||
|
||||
it 'notes the error' do |
||||
instance.validate |
||||
expect(instance.errors.details[:widgets]) |
||||
.to match_array [{ error: :inclusion }] |
||||
end |
||||
end |
||||
|
||||
context 'collisions between widgets' do |
||||
before do |
||||
grid.widgets.build(start_row: 1, |
||||
end_row: 3, |
||||
start_column: 1, |
||||
end_column: 3, |
||||
identifier: 'work_packages_assigned') |
||||
grid.widgets.build(start_row: 2, |
||||
end_row: 4, |
||||
start_column: 2, |
||||
end_column: 4, |
||||
identifier: 'work_packages_created') |
||||
end |
||||
|
||||
it 'is invalid' do |
||||
expect(instance.validate) |
||||
.to be_falsey |
||||
end |
||||
|
||||
it 'notes the error' do |
||||
instance.validate |
||||
expect(instance.errors.details[:widgets]) |
||||
.to match_array [{ error: :overlaps }, { error: :overlaps }] |
||||
end |
||||
end |
||||
|
||||
context 'widgets having the same start column as another\'s end column' do |
||||
before do |
||||
grid.widgets.build(start_row: 1, |
||||
end_row: 3, |
||||
start_column: 1, |
||||
end_column: 3, |
||||
identifier: 'work_packages_assigned') |
||||
grid.widgets.build(start_row: 1, |
||||
end_row: 3, |
||||
start_column: 3, |
||||
end_column: 4, |
||||
identifier: 'work_packages_created') |
||||
end |
||||
|
||||
it 'is valid' do |
||||
expect(instance.validate) |
||||
.to be_truthy |
||||
end |
||||
end |
||||
|
||||
context 'widgets having the same start row as another\'s end row' do |
||||
before do |
||||
grid.widgets.build(start_row: 1, |
||||
end_row: 3, |
||||
start_column: 1, |
||||
end_column: 3, |
||||
identifier: 'work_packages_assigned') |
||||
grid.widgets.build(start_row: 3, |
||||
end_row: 4, |
||||
start_column: 1, |
||||
end_column: 3, |
||||
identifier: 'work_packages_created') |
||||
end |
||||
|
||||
it 'is valid' do |
||||
expect(instance.validate) |
||||
.to be_truthy |
||||
end |
||||
end |
||||
|
||||
context 'widgets being outside (max) of the grid' do |
||||
before do |
||||
grid.widgets.build(start_row: 1, |
||||
end_row: grid.row_count + 2, |
||||
start_column: 1, |
||||
end_column: 3, |
||||
identifier: 'work_packages_assigned') |
||||
end |
||||
|
||||
it 'is invalid' do |
||||
expect(instance.validate) |
||||
.to be_falsey |
||||
end |
||||
|
||||
it 'notes the error' do |
||||
instance.validate |
||||
expect(instance.errors.details[:widgets]) |
||||
.to match_array [{ error: :outside }] |
||||
end |
||||
end |
||||
|
||||
context 'widgets being outside (min) of the grid' do |
||||
before do |
||||
grid.widgets.build(start_row: 1, |
||||
end_row: 2, |
||||
start_column: -1, |
||||
end_column: 3, |
||||
identifier: 'work_packages_assigned') |
||||
end |
||||
|
||||
it 'is invalid' do |
||||
expect(instance.validate) |
||||
.to be_falsey |
||||
end |
||||
|
||||
it 'notes the error' do |
||||
instance.validate |
||||
expect(instance.errors.details[:widgets]) |
||||
.to match_array [{ error: :outside }] |
||||
end |
||||
end |
||||
|
||||
context 'widgets spanning the whole grid' do |
||||
before do |
||||
grid.widgets.build(start_row: 1, |
||||
end_row: grid.row_count + 1, |
||||
start_column: 1, |
||||
end_column: grid.column_count + 1, |
||||
identifier: 'work_packages_assigned') |
||||
end |
||||
|
||||
it 'is valid' do |
||||
expect(instance.validate) |
||||
.to be_truthy |
||||
end |
||||
end |
||||
|
||||
context 'widgets having start after end column' do |
||||
before do |
||||
grid.widgets.build(start_row: 1, |
||||
end_row: 2, |
||||
start_column: 4, |
||||
end_column: 3, |
||||
identifier: 'work_packages_assigned') |
||||
end |
||||
|
||||
it 'is invalid' do |
||||
expect(instance.validate) |
||||
.to be_falsey |
||||
end |
||||
|
||||
it 'notes the error' do |
||||
instance.validate |
||||
expect(instance.errors.details[:widgets]) |
||||
.to match_array [{ error: :end_before_start }] |
||||
end |
||||
end |
||||
|
||||
context 'widgets having start after end row' do |
||||
before do |
||||
grid.widgets.build(start_row: 4, |
||||
end_row: 2, |
||||
start_column: 1, |
||||
end_column: 3, |
||||
identifier: 'work_packages_assigned') |
||||
end |
||||
|
||||
it 'is invalid' do |
||||
expect(instance.validate) |
||||
.to be_falsey |
||||
end |
||||
|
||||
it 'notes the error' do |
||||
instance.validate |
||||
expect(instance.errors.details[:widgets]) |
||||
.to match_array [{ error: :end_before_start }] |
||||
end |
||||
end |
||||
|
||||
context 'widgets having start equals end column' do |
||||
before do |
||||
grid.widgets.build(start_row: 1, |
||||
end_row: 2, |
||||
start_column: 4, |
||||
end_column: 3, |
||||
identifier: 'work_packages_assigned') |
||||
end |
||||
|
||||
it 'is invalid' do |
||||
expect(instance.validate) |
||||
.to be_falsey |
||||
end |
||||
|
||||
it 'notes the error' do |
||||
instance.validate |
||||
expect(instance.errors.details[:widgets]) |
||||
.to match_array [{ error: :end_before_start }] |
||||
end |
||||
end |
||||
|
||||
context 'widgets having start equals end row' do |
||||
before do |
||||
grid.widgets.build(start_row: 2, |
||||
end_row: 2, |
||||
start_column: 1, |
||||
end_column: 3, |
||||
identifier: 'work_packages_assigned') |
||||
end |
||||
|
||||
it 'is invalid' do |
||||
expect(instance.validate) |
||||
.to be_falsey |
||||
end |
||||
|
||||
it 'notes the error' do |
||||
instance.validate |
||||
expect(instance.errors.details[:widgets]) |
||||
.to match_array [{ error: :end_before_start }] |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'valid grid subclasses' do |
||||
context 'for a registered subclass' do |
||||
let(:grid) do |
||||
FactoryBot.build_stubbed(:my_page, default_values) |
||||
end |
||||
|
||||
it 'is valid' do |
||||
expect(instance.validate) |
||||
.to be_truthy |
||||
end |
||||
end |
||||
|
||||
context 'for the Grid superclass itself' do |
||||
let(:grid) do |
||||
FactoryBot.build_stubbed(:grid, default_values) |
||||
end |
||||
|
||||
before do |
||||
instance.validate |
||||
end |
||||
|
||||
it 'is invalid for the grid superclass itself' do |
||||
expect(instance.errors.details[:scope]) |
||||
.to match_array [{ error: :inclusion }] |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,39 @@ |
||||
#-- 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. |
||||
#++ |
||||
|
||||
require 'spec_helper' |
||||
require_relative './shared_examples' |
||||
|
||||
describe Grids::UpdateContract do |
||||
include_context 'model contract' |
||||
include_context 'grid contract' |
||||
|
||||
it_behaves_like 'shared grid contract attributes' |
||||
end |
@ -0,0 +1,25 @@ |
||||
FactoryBot.define do |
||||
factory :my_page, class: Grids::MyPage do |
||||
user |
||||
row_count { 7 } |
||||
column_count { 4 } |
||||
widgets do |
||||
[ |
||||
Grids::Widget.new( |
||||
identifier: 'work_packages_assigned', |
||||
start_row: 1, |
||||
end_row: 7, |
||||
start_column: 1, |
||||
end_column: 3 |
||||
), |
||||
Grids::Widget.new( |
||||
identifier: 'work_packages_created', |
||||
start_row: 1, |
||||
end_row: 7, |
||||
start_column: 3, |
||||
end_column: 5 |
||||
) |
||||
] |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,77 @@ |
||||
#-- 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. |
||||
#++ |
||||
|
||||
shared_examples_for 'grid attributes' do |
||||
describe 'attributes' do |
||||
it '#row_count' do |
||||
instance.row_count = 5 |
||||
expect(instance.row_count) |
||||
.to eql 5 |
||||
end |
||||
|
||||
it '#column_count' do |
||||
instance.column_count = 5 |
||||
expect(instance.column_count) |
||||
.to eql 5 |
||||
end |
||||
|
||||
it '#name' do |
||||
instance.name = 'custom 123' |
||||
expect(instance.name) |
||||
.to eql 'custom 123' |
||||
|
||||
# can be empty |
||||
instance.name = nil |
||||
expect(instance).to be_valid |
||||
end |
||||
|
||||
it '#options' do |
||||
value = { |
||||
some: 'value', |
||||
and: { |
||||
also: 1 |
||||
} |
||||
} |
||||
|
||||
instance.options = value |
||||
expect(instance.options) |
||||
.to eql value |
||||
end |
||||
|
||||
it '#widgets' do |
||||
widgets = [ |
||||
Grids::Widget.new(start_row: 2), |
||||
Grids::Widget.new(start_row: 5) |
||||
] |
||||
|
||||
instance.widgets = widgets |
||||
expect(instance.widgets) |
||||
.to match_array widgets |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,193 @@ |
||||
#-- 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' |
||||
require 'rack/test' |
||||
|
||||
describe "POST /api/v3/grids/form", type: :request, content_type: :json do |
||||
include Rack::Test::Methods |
||||
include API::V3::Utilities::PathHelper |
||||
|
||||
shared_let(:current_user) do |
||||
FactoryBot.create(:user) |
||||
end |
||||
|
||||
let(:path) { api_v3_paths.create_grid_form } |
||||
let(:params) { {} } |
||||
subject(:response) { last_response } |
||||
|
||||
before do |
||||
login_as(current_user) |
||||
end |
||||
|
||||
describe '#post' do |
||||
before do |
||||
post path, params.to_json, 'CONTENT_TYPE' => 'application/json' |
||||
end |
||||
|
||||
it 'contains a Schema embedding the available values' do |
||||
expect(subject.body) |
||||
.to be_json_eql("Schema".to_json) |
||||
.at_path('_embedded/schema/_type') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql(my_page_path.to_json) |
||||
.at_path('_embedded/schema/scope/_links/allowedValues/0/href') |
||||
end |
||||
|
||||
context 'with /my/page for the scope value' do |
||||
let(:params) do |
||||
{ |
||||
'_links': { |
||||
'scope': { |
||||
'href': my_page_path |
||||
} |
||||
} |
||||
} |
||||
end |
||||
|
||||
it 'contains default data in the payload' do |
||||
expected = { |
||||
"rowCount": 7, |
||||
"columnCount": 4, |
||||
"options": {}, |
||||
"widgets": [ |
||||
{ |
||||
"_type": "GridWidget", |
||||
identifier: 'work_packages_assigned', |
||||
"options": {}, |
||||
startRow: 1, |
||||
endRow: 7, |
||||
startColumn: 1, |
||||
endColumn: 3 |
||||
}, |
||||
{ |
||||
"_type": "GridWidget", |
||||
identifier: 'work_packages_created', |
||||
"options": {}, |
||||
startRow: 1, |
||||
endRow: 7, |
||||
startColumn: 3, |
||||
endColumn: 5 |
||||
} |
||||
], |
||||
"_links": { |
||||
"scope": { |
||||
"href": "/my/page", |
||||
"type": "text/html" |
||||
} |
||||
} |
||||
} |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql(expected.to_json) |
||||
.at_path('_embedded/payload') |
||||
end |
||||
|
||||
it 'has no validationErrors' do |
||||
expect(subject.body) |
||||
.to be_json_eql({}.to_json) |
||||
.at_path('_embedded/validationErrors') |
||||
end |
||||
|
||||
it 'has a commit link' do |
||||
expect(subject.body) |
||||
.to be_json_eql(api_v3_paths.grids.to_json) |
||||
.at_path('_links/commit/href') |
||||
end |
||||
end |
||||
|
||||
context 'with an unsupported widget identifier' do |
||||
let(:params) do |
||||
{ |
||||
'_links': { |
||||
'scope': { |
||||
'href': my_page_path |
||||
} |
||||
}, |
||||
"widgets": [ |
||||
{ |
||||
"_type": "GridWidget", |
||||
"identifier": "bogus_identifier", |
||||
"startRow": 4, |
||||
"endRow": 5, |
||||
"startColumn": 1, |
||||
"endColumn": 2 |
||||
} |
||||
] |
||||
} |
||||
end |
||||
|
||||
it 'has a validationError on widget' do |
||||
expect(subject.body) |
||||
.to be_json_eql("Widgets is not set to one of the allowed values.".to_json) |
||||
.at_path('_embedded/validationErrors/widgets/message') |
||||
end |
||||
end |
||||
|
||||
context 'with name set' do |
||||
let(:params) do |
||||
{ |
||||
name: 'My custom grid 1', |
||||
'_links': { |
||||
'scope': { |
||||
'href': my_page_path |
||||
} |
||||
} |
||||
} |
||||
end |
||||
|
||||
it 'feeds it back' do |
||||
expect(subject.body) |
||||
.to be_json_eql("My custom grid 1".to_json) |
||||
.at_path('_embedded/payload/name') |
||||
end |
||||
end |
||||
|
||||
context 'with options set' do |
||||
let(:params) do |
||||
{ |
||||
options: { |
||||
foo: 'bar' |
||||
}, |
||||
'_links': { |
||||
'scope': { |
||||
'href': my_page_path |
||||
} |
||||
} |
||||
} |
||||
end |
||||
|
||||
it 'feeds them back' do |
||||
expect(subject.body) |
||||
.to be_json_eql("bar".to_json) |
||||
.at_path('_embedded/payload/options/foo') |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,414 @@ |
||||
#-- 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' |
||||
require 'rack/test' |
||||
|
||||
describe 'API v3 Grids resource', type: :request, content_type: :json do |
||||
include Rack::Test::Methods |
||||
include API::V3::Utilities::PathHelper |
||||
|
||||
shared_let(:current_user) do |
||||
FactoryBot.create(:user) |
||||
end |
||||
|
||||
let(:my_page_grid) { FactoryBot.create(:my_page, user: current_user) } |
||||
let(:other_user) do |
||||
FactoryBot.create(:user) |
||||
end |
||||
let(:other_my_page_grid) { FactoryBot.create(:my_page, user: other_user) } |
||||
|
||||
before do |
||||
login_as(current_user) |
||||
end |
||||
|
||||
subject(:response) { last_response } |
||||
|
||||
describe '#get INDEX' do |
||||
let(:path) { api_v3_paths.grids } |
||||
|
||||
let(:stored_grids) do |
||||
my_page_grid |
||||
other_my_page_grid |
||||
end |
||||
|
||||
before do |
||||
stored_grids |
||||
|
||||
get path |
||||
end |
||||
|
||||
it 'sends a collection of grids but only those visible to the current user' do |
||||
expect(subject.body) |
||||
.to be_json_eql('Collection'.to_json) |
||||
.at_path('_type') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql('Grid'.to_json) |
||||
.at_path('_embedded/elements/0/_type') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql(1.to_json) |
||||
.at_path('total') |
||||
end |
||||
|
||||
context 'with a filter on the scope attribute' do |
||||
shared_let(:other_grid) do |
||||
grid = Grids::Grid.new(row_count: 20, |
||||
column_count: 20) |
||||
grid.save |
||||
|
||||
Grids::Grid |
||||
.where(id: grid.id) |
||||
.update_all(user_id: current_user.id) |
||||
|
||||
grid |
||||
end |
||||
|
||||
let(:stored_grids) do |
||||
my_page_grid |
||||
other_my_page_grid |
||||
other_grid |
||||
end |
||||
|
||||
let(:path) do |
||||
filter = [{ 'scope' => |
||||
{ |
||||
'operator' => '=', |
||||
'values' => [my_page_path] |
||||
} }] |
||||
|
||||
"#{api_v3_paths.grids}?#{{ filters: filter.to_json }.to_query}" |
||||
end |
||||
|
||||
it 'responds with 200 OK' do |
||||
expect(subject.status).to eq(200) |
||||
end |
||||
|
||||
it 'sends only the my page of the current user' do |
||||
expect(subject.body) |
||||
.to be_json_eql('Collection'.to_json) |
||||
.at_path('_type') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql('Grid'.to_json) |
||||
.at_path('_embedded/elements/0/_type') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql(1.to_json) |
||||
.at_path('total') |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe '#get' do |
||||
let(:path) { api_v3_paths.grid(my_page_grid.id) } |
||||
|
||||
let(:stored_grids) do |
||||
my_page_grid |
||||
end |
||||
|
||||
before do |
||||
stored_grids |
||||
|
||||
get path |
||||
end |
||||
|
||||
it 'responds with 200 OK' do |
||||
expect(subject.status).to eq(200) |
||||
end |
||||
|
||||
it 'sends a grid block' do |
||||
expect(subject.body) |
||||
.to be_json_eql('Grid'.to_json) |
||||
.at_path('_type') |
||||
end |
||||
|
||||
it 'identifies the url the grid is stored for' do |
||||
expect(subject.body) |
||||
.to be_json_eql(my_page_path.to_json) |
||||
.at_path('_links/scope/href') |
||||
end |
||||
|
||||
context 'with the page not existing' do |
||||
let(:path) { api_v3_paths.grid(5) } |
||||
|
||||
it 'responds with 404 NOT FOUND' do |
||||
expect(subject.status).to eql 404 |
||||
end |
||||
end |
||||
|
||||
context 'with the grid belonging to someone else' do |
||||
let(:stored_grids) do |
||||
my_page_grid |
||||
other_my_page_grid |
||||
end |
||||
|
||||
let(:path) { api_v3_paths.grid(other_my_page_grid.id) } |
||||
|
||||
it 'responds with 404 NOT FOUND' do |
||||
expect(subject.status).to eql 404 |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe '#patch' do |
||||
let(:path) { api_v3_paths.grid(my_page_grid.id) } |
||||
|
||||
let(:params) do |
||||
{ |
||||
"rowCount": 10, |
||||
"name": 'foo', |
||||
"columnCount": 15, |
||||
"widgets": [{ |
||||
"identifier": "work_packages_assigned", |
||||
"startRow": 4, |
||||
"endRow": 8, |
||||
"startColumn": 2, |
||||
"endColumn": 5 |
||||
}] |
||||
}.with_indifferent_access |
||||
end |
||||
|
||||
let(:stored_grids) do |
||||
my_page_grid |
||||
end |
||||
|
||||
before do |
||||
stored_grids |
||||
|
||||
patch path, params.to_json, 'CONTENT_TYPE' => 'application/json' |
||||
end |
||||
|
||||
it 'responds with 200 OK' do |
||||
expect(subject.status).to eq(200) |
||||
end |
||||
|
||||
it 'returns the altered grid block' do |
||||
expect(subject.body) |
||||
.to be_json_eql('Grid'.to_json) |
||||
.at_path('_type') |
||||
expect(subject.body) |
||||
.to be_json_eql('foo'.to_json) |
||||
.at_path('name') |
||||
expect(subject.body) |
||||
.to be_json_eql(params['rowCount'].to_json) |
||||
.at_path('rowCount') |
||||
expect(subject.body) |
||||
.to be_json_eql(params['widgets'][0]['identifier'].to_json) |
||||
.at_path('widgets/0/identifier') |
||||
end |
||||
|
||||
it 'perists the changes' do |
||||
expect(my_page_grid.reload.row_count) |
||||
.to eql params['rowCount'] |
||||
end |
||||
|
||||
context 'with invalid params' do |
||||
let(:params) do |
||||
{ |
||||
"rowCount": -5, |
||||
"columnCount": 15, |
||||
"widgets": [{ |
||||
"identifier": "work_packages_assigned", |
||||
"startRow": 4, |
||||
"endRow": 8, |
||||
"startColumn": 2, |
||||
"endColumn": 5 |
||||
}] |
||||
}.with_indifferent_access |
||||
end |
||||
|
||||
it 'responds with 422 and mentions the error' do |
||||
expect(subject.status).to eq 422 |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql('Error'.to_json) |
||||
.at_path('_type') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql("Widgets is outside of the grid.".to_json) |
||||
.at_path('_embedded/errors/0/message') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql("Number of rows must be greater than 0.".to_json) |
||||
.at_path('_embedded/errors/1/message') |
||||
end |
||||
|
||||
it 'does not persist the changes to widgets' do |
||||
expect(my_page_grid.reload.widgets.count) |
||||
.to eql MyPage::GridRegistration.defaults[:widgets].size |
||||
end |
||||
end |
||||
|
||||
context 'with a scope param' do |
||||
let(:params) do |
||||
{ |
||||
"_links": { |
||||
"scope": { |
||||
"href": '' |
||||
} |
||||
} |
||||
}.with_indifferent_access |
||||
end |
||||
|
||||
it 'responds with 422 and mentions the error' do |
||||
expect(subject.status).to eq 422 |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql('Error'.to_json) |
||||
.at_path('_type') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql("You must not write a read-only attribute.".to_json) |
||||
.at_path('message') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql("scope".to_json) |
||||
.at_path('_embedded/details/attribute') |
||||
end |
||||
end |
||||
|
||||
context 'with the page not existing' do |
||||
let(:path) { api_v3_paths.grid(5) } |
||||
|
||||
it 'responds with 404 NOT FOUND' do |
||||
expect(subject.status).to eql 404 |
||||
end |
||||
end |
||||
|
||||
context 'with the grid belonging to someone else' do |
||||
let(:stored_grids) do |
||||
my_page_grid |
||||
other_my_page_grid |
||||
end |
||||
|
||||
let(:path) { api_v3_paths.grid(other_my_page_grid.id) } |
||||
|
||||
it 'responds with 404 NOT FOUND' do |
||||
expect(subject.status).to eql 404 |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe '#post' do |
||||
let(:path) { api_v3_paths.grids } |
||||
|
||||
let(:params) do |
||||
{ |
||||
"rowCount": 10, |
||||
"columnCount": 15, |
||||
"widgets": [{ |
||||
"identifier": "work_packages_assigned", |
||||
"startRow": 4, |
||||
"endRow": 8, |
||||
"startColumn": 2, |
||||
"endColumn": 5 |
||||
}], |
||||
"_links": { |
||||
"scope": { |
||||
"href": my_page_path |
||||
} |
||||
} |
||||
}.with_indifferent_access |
||||
end |
||||
|
||||
before do |
||||
post path, params.to_json, 'CONTENT_TYPE' => 'application/json' |
||||
end |
||||
|
||||
it 'responds with 201 CREATED' do |
||||
expect(subject.status).to eq(201) |
||||
end |
||||
|
||||
it 'returns the created grid block' do |
||||
expect(subject.body) |
||||
.to be_json_eql('Grid'.to_json) |
||||
.at_path('_type') |
||||
expect(subject.body) |
||||
.to be_json_eql(params['rowCount'].to_json) |
||||
.at_path('rowCount') |
||||
expect(subject.body) |
||||
.to be_json_eql(params['widgets'][0]['identifier'].to_json) |
||||
.at_path('widgets/0/identifier') |
||||
end |
||||
|
||||
it 'persists the grid' do |
||||
expect(Grids::Grid.count) |
||||
.to eql(1) |
||||
end |
||||
|
||||
context 'with invalid params' do |
||||
let(:params) do |
||||
{ |
||||
"rowCount": -5, |
||||
"columnCount": "sdjfksdfsdfdsf", |
||||
"widgets": [{ |
||||
"identifier": "work_packages_assigned", |
||||
"startRow": 4, |
||||
"endRow": 8, |
||||
"startColumn": 2, |
||||
"endColumn": 5 |
||||
}], |
||||
"_links": { |
||||
"scope": { |
||||
"href": my_page_path |
||||
} |
||||
} |
||||
}.with_indifferent_access |
||||
end |
||||
|
||||
it 'responds with 422' do |
||||
expect(subject.status).to eq(422) |
||||
end |
||||
|
||||
it 'does not create a grid' do |
||||
expect(Grids::Grid.count) |
||||
.to eql(0) |
||||
end |
||||
|
||||
it 'returns the errors' do |
||||
expect(subject.body) |
||||
.to be_json_eql('Error'.to_json) |
||||
.at_path('_type') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql("Widgets is outside of the grid.".to_json) |
||||
.at_path('_embedded/errors/0/message') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql("Number of rows must be greater than 0.".to_json) |
||||
.at_path('_embedded/errors/1/message') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql("Number of columns must be greater than 0.".to_json) |
||||
.at_path('_embedded/errors/2/message') |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,174 @@ |
||||
#-- 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' |
||||
require 'rack/test' |
||||
|
||||
describe "PATCH /api/v3/grids/:id/form", type: :request, content_type: :json do |
||||
include Rack::Test::Methods |
||||
include API::V3::Utilities::PathHelper |
||||
|
||||
shared_let(:current_user) do |
||||
FactoryBot.create(:user) |
||||
end |
||||
|
||||
let(:grid) do |
||||
FactoryBot.create(:my_page, user: current_user) |
||||
end |
||||
let(:path) { api_v3_paths.grid_form(grid.id) } |
||||
let(:params) { {} } |
||||
subject(:response) { last_response } |
||||
|
||||
before do |
||||
login_as(current_user) |
||||
end |
||||
|
||||
describe '#post' do |
||||
before do |
||||
post path, params.to_json, 'CONTENT_TYPE' => 'application/json' |
||||
end |
||||
|
||||
it 'returns 200 OK' do |
||||
expect(subject.status) |
||||
.to eql 200 |
||||
end |
||||
|
||||
it 'is of type form' do |
||||
expect(subject.body) |
||||
.to be_json_eql("Form".to_json) |
||||
.at_path('_type') |
||||
end |
||||
|
||||
it 'contains a Schema disallowing setting scope' do |
||||
expect(subject.body) |
||||
.to be_json_eql("Schema".to_json) |
||||
.at_path('_embedded/schema/_type') |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql(false.to_json) |
||||
.at_path('_embedded/schema/scope/writable') |
||||
end |
||||
|
||||
it 'contains the current data in the payload' do |
||||
expected = { |
||||
rowCount: 7, |
||||
columnCount: 4, |
||||
options: {}, |
||||
widgets: [ |
||||
{ |
||||
"_type": "GridWidget", |
||||
identifier: 'work_packages_assigned', |
||||
options: {}, |
||||
startRow: 1, |
||||
endRow: 7, |
||||
startColumn: 1, |
||||
endColumn: 3 |
||||
}, |
||||
{ |
||||
"_type": "GridWidget", |
||||
identifier: 'work_packages_created', |
||||
options: {}, |
||||
startRow: 1, |
||||
endRow: 7, |
||||
startColumn: 3, |
||||
endColumn: 5 |
||||
} |
||||
], |
||||
"_links": { |
||||
"scope": { |
||||
"href": "/my/page", |
||||
"type": "text/html" |
||||
} |
||||
} |
||||
} |
||||
|
||||
expect(subject.body) |
||||
.to be_json_eql(expected.to_json) |
||||
.at_path('_embedded/payload') |
||||
end |
||||
|
||||
it 'has a commit link' do |
||||
expect(subject.body) |
||||
.to be_json_eql(api_v3_paths.grid(grid.id).to_json) |
||||
.at_path('_links/commit/href') |
||||
end |
||||
|
||||
context 'with some value for the scope value' do |
||||
let(:params) do |
||||
{ |
||||
'_links': { |
||||
'scope': { |
||||
'href': '/some/path' |
||||
} |
||||
} |
||||
} |
||||
end |
||||
|
||||
it 'has a validation error on scope as the value is not writeable' do |
||||
expect(subject.body) |
||||
.to be_json_eql("You must not write a read-only attribute.".to_json) |
||||
.at_path('_embedded/validationErrors/scope/message') |
||||
end |
||||
end |
||||
|
||||
context 'with an unsupported widget identifier' do |
||||
let(:params) do |
||||
{ |
||||
"widgets": [ |
||||
{ |
||||
"_type": "GridWidget", |
||||
"identifier": "bogus_identifier", |
||||
"startRow": 4, |
||||
"endRow": 5, |
||||
"startColumn": 1, |
||||
"endColumn": 2 |
||||
} |
||||
] |
||||
} |
||||
end |
||||
|
||||
it 'has a validationError on widget' do |
||||
expect(subject.body) |
||||
.to be_json_eql("Widgets is not set to one of the allowed values.".to_json) |
||||
.at_path('_embedded/validationErrors/widgets/message') |
||||
end |
||||
end |
||||
|
||||
context 'for another user\'s grid' do |
||||
let(:other_user) { FactoryBot.create(:user) } |
||||
let(:other_grid) { FactoryBot.create(:my_page, user: other_user) } |
||||
|
||||
let(:path) { api_v3_paths.grid_form(other_grid.id) } |
||||
|
||||
it 'returns 404 NOT FOUND' do |
||||
expect(subject.status) |
||||
.to eql 404 |
||||
end |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue