Initial foundations for API v3

User Story # 8769

Squashed commit of the following:

commit fac82d68b6
Author: Marek Takac <m.takac@finn.de>
Date:   Wed Jun 11 15:53:21 2014 +0200

    Removed cascade false call from root api

commit fedff52220
Merge: 7b2942c e204fa9
Author: Marek Takac <m.takac@finn.de>
Date:   Wed Jun 11 14:17:27 2014 +0200

    Merge

commit 7b2942c419
Author: Marek Takac <m.takac@finn.de>
Date:   Wed Jun 11 14:11:58 2014 +0200

    Generated new Gemfile.lock

commit 7af2f77bbc
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 10 15:03:47 2014 +0200

    Removed print call

commit bb19cddee9
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 10 14:39:35 2014 +0200

    Removed 'spec/factories/priority_factory.rb

commit e8bbf476f1
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 10 14:38:31 2014 +0200

    Replaced lambda calls with '->'

commit 9d8a1c2423
Author: Marek Takac <m.takac@finn.de>
Date:   Fri Jun 6 19:19:40 2014 +0200

    Clean up

commit 08f80e8c91
Author: Marek Takac <m.takac@finn.de>
Date:   Fri Jun 6 19:03:38 2014 +0200

    Delete ::ConnectionManagement-call(env)>

commit 190c2e2d86
Author: Marek Takac <m.takac@finn.de>
Date:   Fri Jun 6 17:40:34 2014 +0200

    Reset Gemfile.lock

commit 0a32dcaef0
Author: Marek Takac <m.takac@finn.de>
Date:   Fri Jun 6 14:43:58 2014 +0200

    Small refactoring of the API specs

commit 963bb3e848
Author: Marek Takac <m.takac@finn.de>
Date:   Wed Jun 4 17:10:15 2014 +0200

    Basic implementation of APIv3 work package #get

commit ffdb5641a7
Author: Marek Takac <m.takac@finn.de>
Date:   Wed Jun 4 17:08:48 2014 +0200

    Basic implementation of APIv3 work package #get

commit 8d64840f02
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 3 16:33:02 2014 +0200

    Clening up

commit 2caf393c94
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 3 16:30:50 2014 +0200

    Work package #patch - incomplete tests

commit d6b9a4f263
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 28 17:42:26 2014 +0200

    Renamed #done_ratio to #percentage_done

commit 583ba0b525
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 28 17:30:42 2014 +0200

    Cleanup

commit 34bfb88377
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 28 17:14:09 2014 +0200

    Added basic test & improved patch work package

commit 377070acfe
Author: Marek Takac <m.takac@finn.de>
Date:   Fri May 23 15:38:58 2014 +0200

    Implemented basic batch update for work packages

commit 9df0ffb916
Author: Marek Takac <m.takac@finn.de>
Date:   Fri May 23 14:41:56 2014 +0200

    Set default limit and offset for GET work packages resource

commit f1ac16b23f
Author: Marek Takac <m.takac@finn.de>
Date:   Fri May 23 14:18:00 2014 +0200

    Created GET endpoint work work packages resource & N+1 query optimization

commit 9a7bb32f46
Author: Marek Takac <m.takac@finn.de>
Date:   Thu May 22 19:29:04 2014 +0200

    Basic authorization for work package GET and PATCH

commit da4b778d51
Author: Marek Takac <m.takac@finn.de>
Date:   Thu May 22 15:51:10 2014 +0200

    Completed basic implementation of get, patch, head and options requests for work package resource

commit c8e8ab68af
Author: Marek Takac <m.takac@finn.de>
Date:   Thu May 22 10:47:43 2014 +0200

    Added target version attributes to the work package resource

commit 2ab0bea6ac
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 21 18:08:13 2014 +0200

    Implemented work package update with some child resources

commit 17edd10bb5
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 21 16:31:18 2014 +0200

    Minor refactoring of work packages api

commit a63f17622c
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 21 16:28:48 2014 +0200

    Created GET work package endpoint

commit abcf2e50b4
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 20 14:40:47 2014 +0200

    Created OP API entry point

commit 4564bae6f5
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 20 13:39:57 2014 +0200

    Refactor authorize method (created service object)

commit cb464d9329
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 20 11:15:31 2014 +0200

    Created basic structure for Work packages API

commit 00f3b7a291
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 13 16:29:30 2014 +0200

    WorkPackage mapper changes

commit 622ebd04eb
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 13 01:30:02 2014 +0200

    Added relationships to WorkPackage mapper

commit 80ebe54d90
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 13 01:14:57 2014 +0200

    Created WorkPackage mapper class

commit 2da9225aef
Author: Marek Takac <m.takac@finn.de>
Date:   Mon May 12 19:21:07 2014 +0200

    Mappers for Grape API

commit 5cd59c4ad6
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Apr 29 16:54:24 2014 +0200

    Created some decorators

commit a5cb66e5b6
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Apr 29 15:31:25 2014 +0200

    Added pundit for authorization

commit f909e89687
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Apr 29 14:49:20 2014 +0200

    Created work package representer & current_user helper method for API

commit 5aad3c087a
Author: Marek Takac <m.takac@finn.de>
Date:   Mon Apr 28 14:24:47 2014 +0200

    Created basic structure for Work packages API

commit b25a348619
Author: Marek Takac <m.takac@finn.de>
Date:   Mon Apr 28 14:04:37 2014 +0200

    Set up Grape API v3

commit be76a6500e
Author: Marek Takac <m.takac@finn.de>
Date:   Mon Apr 28 13:58:38 2014 +0200

    Added grape

commit e204fa9de8
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 10 15:03:47 2014 +0200

    Removed print call

commit 39b921adc7
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 10 14:39:35 2014 +0200

    Removed 'spec/factories/priority_factory.rb

commit 94c64ab855
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 10 14:38:31 2014 +0200

    Replaced lambda calls with '->'

commit c2101b0352
Author: Marek Takac <m.takac@finn.de>
Date:   Fri Jun 6 19:19:40 2014 +0200

    Clean up

commit a03bc0d84c
Author: Marek Takac <m.takac@finn.de>
Date:   Fri Jun 6 19:03:38 2014 +0200

    Delete ::ConnectionManagement-call(env)>

commit 8b2fe0b01e
Author: Marek Takac <m.takac@finn.de>
Date:   Fri Jun 6 17:40:34 2014 +0200

    Reset Gemfile.lock

commit 5d6618eea4
Merge: f325a36 dab75c3
Author: Marek Takac <m.takac@finn.de>
Date:   Fri Jun 6 16:10:51 2014 +0200

    Merge branch 'dev' into feature/api_v3_base

commit f325a36d6f
Author: Marek Takac <m.takac@finn.de>
Date:   Fri Jun 6 14:43:58 2014 +0200

    Small refactoring of the API specs

commit 84f78d669d
Author: Marek Takac <m.takac@finn.de>
Date:   Wed Jun 4 17:10:15 2014 +0200

    Basic implementation of APIv3 work package #get

commit 82786a9717
Author: Marek Takac <m.takac@finn.de>
Date:   Wed Jun 4 17:08:48 2014 +0200

    Basic implementation of APIv3 work package #get

commit b7dd82f85f
Merge: f4ba4e8 5525bc3
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 3 17:15:48 2014 +0200

    Merge

commit 5525bc3d52
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 3 16:33:02 2014 +0200

    Clening up

commit 9d27e3d412
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Jun 3 16:30:50 2014 +0200

    Work package #patch - incomplete tests

commit 58ceeee83e
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 28 17:42:26 2014 +0200

    Renamed #done_ratio to #percentage_done

commit 7165e32bc4
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 28 17:30:42 2014 +0200

    Cleanup

commit 235ecdeabe
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 28 17:14:09 2014 +0200

    Added basic test & improved patch work package

commit 625f273dc1
Author: Marek Takac <m.takac@finn.de>
Date:   Fri May 23 15:38:58 2014 +0200

    Implemented basic batch update for work packages

commit 20239886d4
Author: Marek Takac <m.takac@finn.de>
Date:   Fri May 23 14:41:56 2014 +0200

    Set default limit and offset for GET work packages resource

commit ad79163fd3
Author: Marek Takac <m.takac@finn.de>
Date:   Fri May 23 14:18:00 2014 +0200

    Created GET endpoint work work packages resource & N+1 query optimization

commit c3dcba77f0
Author: Marek Takac <m.takac@finn.de>
Date:   Thu May 22 19:29:04 2014 +0200

    Basic authorization for work package GET and PATCH

commit 73d8a8551d
Author: Marek Takac <m.takac@finn.de>
Date:   Thu May 22 15:51:10 2014 +0200

    Completed basic implementation of get, patch, head and options requests for work package resource

commit 479fc4b005
Author: Marek Takac <m.takac@finn.de>
Date:   Thu May 22 10:47:43 2014 +0200

    Added target version attributes to the work package resource

commit a72cff36a9
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 21 18:08:13 2014 +0200

    Implemented work package update with some child resources

commit 6689628a74
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 21 16:31:18 2014 +0200

    Minor refactoring of work packages api

commit 97d4e9a1e6
Author: Marek Takac <m.takac@finn.de>
Date:   Wed May 21 16:28:48 2014 +0200

    Created GET work package endpoint

commit 1490621af1
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 20 14:40:47 2014 +0200

    Created OP API entry point

commit 1e080b7936
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 20 13:39:57 2014 +0200

    Refactor authorize method (created service object)

commit 1b0b894456
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 20 11:15:31 2014 +0200

    Created basic structure for Work packages API

commit 6c8f83ae54
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 13 16:29:30 2014 +0200

    WorkPackage mapper changes

commit d2a7f29201
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 13 01:30:02 2014 +0200

    Added relationships to WorkPackage mapper

commit 0122cd4392
Author: Marek Takac <m.takac@finn.de>
Date:   Tue May 13 01:14:57 2014 +0200

    Created WorkPackage mapper class

commit 6a40cdd6bf
Author: Marek Takac <m.takac@finn.de>
Date:   Mon May 12 19:21:07 2014 +0200

    Mappers for Grape API

commit 0a4f39be58
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Apr 29 16:54:24 2014 +0200

    Created some decorators

commit 21e1c42b54
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Apr 29 15:31:25 2014 +0200

    Added pundit for authorization

commit a76f23ec51
Author: Marek Takac <m.takac@finn.de>
Date:   Tue Apr 29 14:49:20 2014 +0200

    Created work package representer & current_user helper method for API

commit 4d92b35994
Author: Marek Takac <m.takac@finn.de>
Date:   Mon Apr 28 14:24:47 2014 +0200

    Created basic structure for Work packages API

commit d19a5d698a
Author: Marek Takac <m.takac@finn.de>
Date:   Mon Apr 28 14:04:37 2014 +0200

    Set up Grape API v3

commit b270fa6164
Author: Marek Takac <m.takac@finn.de>
Date:   Mon Apr 28 13:58:38 2014 +0200

    Added grape

Signed-off-by: Alex Coles <alex@alexbcoles.com>
pull/1462/head
Marek Takac 11 years ago committed by Alex Coles
parent d4770290f3
commit ac2c89c0d7
  1. 10
      Gemfile
  2. 61
      Gemfile.lock
  3. 9
      app/controllers/application_controller.rb
  4. 48
      app/services/authorization_service.rb
  5. 4
      config/application.rb
  6. 11
      config/initializers/reload_api.rb
  7. 2
      config/routes.rb
  8. 5
      db/migrate/20140602112515_drop_work_packages_priority_not_null_constraint.rb
  9. 52
      lib/api/errors/not_found.rb
  10. 51
      lib/api/errors/unauthenticated.rb
  11. 52
      lib/api/errors/unauthorized.rb
  12. 52
      lib/api/errors/unwritable_property.rb
  13. 52
      lib/api/errors/validation.rb
  14. 79
      lib/api/root.rb
  15. 49
      lib/api/utilities/camel_casing_strategy.rb
  16. 42
      lib/api/v3/root.rb
  17. 106
      lib/api/v3/work_packages/work_package_model.rb
  18. 83
      lib/api/v3/work_packages/work_package_representer.rb
  19. 31
      lib/api/v3/work_packages/work_packages_api.rb
  20. 1
      lib/redmine.rb
  21. 121
      spec/api/work_package_resource_spec.rb
  22. 3
      spec/spec_helper.rb

@ -141,8 +141,8 @@ gem 'i18n', '>=0.6.8'
gem 'nokogiri', '>=1.5.11'
# see https://groups.google.com/forum/#!topic/ruby-security-ann/DeJpjTAg1FA
group :test do
gem 'rack-test', '~> 0.6.2'
gem 'shoulda'
gem 'object-daddy', '~> 1.1.0'
gem "launchy", "~> 2.3.0"
@ -188,6 +188,14 @@ group :development do
gem 'quiet_assets'
end
gem 'pundit'
# API gems
gem 'grape', '~> 0.7.0'
gem 'representable', :github => 'finnlabs/representable'
gem 'roar', '~> 0.12.6'
gem 'reform'
# Use the commented pure ruby gems, if you have not the needed prerequisites on
# board to compile the native ones. Note, that their use is discouraged, since
# their integration is propbably not that well tested and their are slower in

@ -1,3 +1,12 @@
GIT
remote: git://github.com/finnlabs/representable.git
revision: 5f8fbcb1e61720699135c39be3f36a725ca870ad
specs:
representable (1.8.1)
multi_json
nokogiri
uber
GIT
remote: https://github.com/Compass/compass-rails
revision: f97a4f41518204683aeec7037da3d9b8c57ef4cb
@ -81,6 +90,10 @@ GEM
arel (3.0.3)
awesome_nested_set (2.1.6)
activerecord (>= 3.0.0)
axiom-types (0.1.1)
descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
bourbon (4.0.0)
@ -110,6 +123,8 @@ GEM
codeclimate-test-reporter (0.1.1)
simplecov (>= 0.7.1, < 1.0.0)
coderay (1.0.9)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
color-tools (1.3.0)
columnize (0.8.9)
compass (1.0.0.alpha.19)
@ -149,7 +164,13 @@ GEM
delayed_job_active_record (0.3.3)
activerecord (>= 2.1.0, < 4)
delayed_job (~> 3.0)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
diff-lcs (1.2.5)
disposable (0.0.4)
representable (~> 1.8.1)
uber
equalizer (0.0.9)
erubis (2.7.0)
eventmachine (1.0.3)
execjs (1.4.0)
@ -171,11 +192,22 @@ GEM
gon (4.0.0)
actionpack (>= 2.3.0)
json
hashie (2.0.5)
grape (0.7.0)
activesupport
builder
hashie (>= 1.2.0)
multi_json (>= 1.3.2)
multi_xml (>= 0.5.2)
rack (>= 1.3.0)
rack-accept
rack-mount
virtus (>= 1.0.0)
hashie (2.1.1)
hike (1.2.3)
hooks (0.3.3)
htmldiff (0.0.1)
i18n (0.6.9)
ice_nine (0.11.0)
interception (0.3)
journey (1.0.4)
json (1.8.1)
@ -210,6 +242,7 @@ GEM
metaclass (~> 0.0.1)
multi_json (1.9.3)
multi_test (0.0.2)
multi_xml (0.5.5)
mysql2 (0.3.11)
net-ldap (0.2.2)
nokogiri (1.5.11)
@ -244,13 +277,19 @@ GEM
pry-stack_explorer (0.4.9.1)
binding_of_caller (>= 0.7)
pry (>= 0.9.11)
pundit (0.2.3)
activesupport (>= 3.0.0)
quiet_assets (1.0.2)
railties (>= 3.1, < 5.0)
rabl (0.9.3)
activesupport (>= 2.3.14)
rack (1.4.5)
rack-accept (0.4.5)
rack (>= 0.4)
rack-cache (1.2)
rack (>= 0.4)
rack-mount (0.8.3)
rack (>= 1.0.0)
rack-ssl (1.3.4)
rack
rack-test (0.6.2)
@ -289,7 +328,14 @@ GEM
json (~> 1.4)
redcarpet (3.0.0)
ref (1.0.5)
reform (1.0.1)
activemodel
disposable (~> 0.0.4)
representable (~> 1.8.1)
uber (~> 0.0.4)
request_store (1.0.5)
roar (0.12.7)
representable (>= 1.6.0)
rspec (2.14.1)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
@ -356,15 +402,22 @@ GEM
eventmachine (>= 0.12.6)
rack (>= 1.0.0)
thor (0.19.1)
thread_safe (0.3.4)
tilt (1.4.1)
timecop (0.6.1)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.38)
uber (0.0.4)
uglifier (2.1.1)
execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2)
virtus (1.0.2)
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0.3)
equalizer (~> 0.0.9)
websocket (1.0.7)
will_paginate (3.0.5)
xpath (2.0.0)
@ -401,6 +454,7 @@ DEPENDENCIES
faker
globalize
gon (~> 4.0)
grape (~> 0.7.0)
htmldiff
i18n (>= 0.6.8)
i18n-js!
@ -425,16 +479,21 @@ DEPENDENCIES
pry-rails
pry-rescue
pry-stack_explorer
pundit
quiet_assets
rabl (= 0.9.3)
rack-protection!
rack-test (~> 0.6.2)
rack_session_access
rails (~> 3.2.18)
rails-dev-tweaks (~> 0.6.1)
rails_autolink
rb-readline
rdoc (>= 2.4.2)
reform
representable!
request_store
roar (~> 0.12.6)
rspec (~> 2.14)
rspec-example_disabler!
rspec-rails (~> 2.14)

@ -288,17 +288,16 @@ class ApplicationController < ActionController::Base
# Authorize the user for the requested action
def authorize(ctrl = params[:controller], action = params[:action], global = false)
allowed = User.current.allowed_to?({ controller: ctrl, action: action },
@project || @projects, :global => global)
if allowed
true
else
is_authorized = AuthorizationService.new(ctrl, action, @project, @projects, global).perform
unless is_authorized
if @project && @project.archived?
render_403 :message => :notice_not_authorized_archived_project
else
deny_access
end
end
is_authorized
end
# Authorize the user for the requested action outside a project

@ -0,0 +1,48 @@
#-- 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.
#++
class AuthorizationService
def initialize(ctrl, action, project, projects, global, user = nil)
@ctrl = ctrl
@action = action
@project = project
@projects = projects
@global = global
@user = user || User.current
end
def perform
allowed = @user.allowed_to?({:controller => @ctrl, :action => @action}, @project || @projects, :global => @global)
if allowed
true
else
false
end
end
end

@ -160,6 +160,10 @@ module OpenProject
ActionMailer::Base.view_paths = ActionView::PathSet.new(ActionMailer::Base.view_paths.to_ary.reverse)
end
# Load API files
config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
OpenProject::Configuration.configure_cache(config)
end
end

@ -0,0 +1,11 @@
if Rails.env.development?
ActiveSupport::Dependencies.explicitly_unloadable_constants << "API"
api_files = Dir[Rails.root.join('app', 'api', '**', '*.rb')]
api_reloader = ActiveSupport::FileUpdateChecker.new(api_files) do
Rails.application.reload_routes!
end
ActionDispatch::Callbacks.to_prepare do
api_reloader.execute_if_updated
end
end

@ -519,4 +519,6 @@ OpenProject::Application.routes.draw do
match '/:controller(/:action(/:id))'
match '/robots' => 'welcome#robots', :defaults => { :format => :txt }
root :to => 'account#login'
mount API::Root => '/'
end

@ -0,0 +1,5 @@
class DropWorkPackagesPriorityNotNullConstraint < ActiveRecord::Migration
def change
change_column :work_packages, :priority_id, :integer, :null => true
end
end

@ -0,0 +1,52 @@
#-- 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.
#++
module API
module Errors
class NotFound < Grape::Exceptions::Base
attr_reader :code, :title, :description, :headers
def initialize(message, args = { })
@message = message
@code = args[:code] || 404
@title = args[:title] || 'not_found'
@description = args[:description] || 'Resource couldn\'t be found.'
@headers = { 'Content-Type' => 'application/hal+json' }.merge(args[:headers] || { })
end
def errors
[{ key: @title, messages: [@message] }]
end
def to_json
{ title: @title, description: @description, errors: errors }.to_json
end
end
end
end

@ -0,0 +1,51 @@
#-- 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.
#++
module API
module Errors
class Unauthenticated < Grape::Exceptions::Base
attr_reader :code, :title, :description, :headers
def initialize(args = { })
@code = args[:code] || 401
@title = args[:title] || 'not_authenticated'
@description = args[:description] || 'User needs to be authenticated to access this resource.'
@headers = { 'Content-Type' => 'application/hal+json' }.merge(args[:headers] || { })
end
def errors
[{ key: @title, messages: ['You need to be authenticated to access this resource'] }]
end
def to_json
{ title: @title, description: @description, errors: errors }.to_json
end
end
end
end

@ -0,0 +1,52 @@
#-- 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.
#++
module API
module Errors
class Unauthorized < Grape::Exceptions::Base
attr_reader :code, :title, :description, :headers
def initialize(user, args = { })
@user = user
@code = args[:code] || 403
@title = args[:title] || 'not_authorized'
@description = args[:description] || 'User does not have sufficent rights to access the resource.'
@headers = { 'Content-Type' => 'application/hal+json' }.merge(args[:headers] || { })
end
def errors
[{ key: @title, messages: ['You are not authorize to access this resource'] }]
end
def to_json
{ title: @title, description: @description, errors: errors }.to_json
end
end
end
end

@ -0,0 +1,52 @@
#-- 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.
#++
module API
module Errors
class UnwritableProperty < Grape::Exceptions::Base
attr_reader :code, :title, :description, :headers
def initialize(property, args = { })
@property = property
@code = args[:code] || 422
@title = args[:title] || 'unwriteable_property_error'
@description = args[:description] || 'You tried to write read-only property.'
@headers = { 'Content-Type' => 'application/hal+json' }.merge(args[:headers] || { })
end
def errors
[{ key: @property, messages: ['is read-only'] }]
end
def to_json
{ title: @title, description: @description, errors: errors }.to_json
end
end
end
end

@ -0,0 +1,52 @@
#-- 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.
#++
module API
module Errors
class Validation < Grape::Exceptions::Base
attr_reader :code, :title, :description, :headers
def initialize(obj, args = { })
@obj = obj
@code = args[:code] || 422
@title = args[:title] || 'validation_error'
@description = args[:description] || 'Validation failed.'
@headers = { 'Content-Type' => 'application/hal+json' }.merge(args[:headers] || { })
end
def errors
@obj.errors.messages.map{ |m| { key: m[0], messages: m[1] }}
end
def to_json
{ title: @title, description: @description, errors: errors }.to_json
end
end
end
end

@ -0,0 +1,79 @@
#-- 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.
#++
# Root class of the API
# This is the place for all API wide configuration, helper methods, exceptions
# rescuing, mounting of differnet API versions etc.
module API
class Root < Grape::API
prefix :api
content_type 'hal+json', 'application/hal+json'
format 'hal+json'
helpers do
# Needs refactoring - Will have to find a way how to access sessions in all enviroments
def current_user
return User.current if Rails.env.test?
if Rails.env.development?
user_id = env['action_dispatch.request.unsigned_session_cookie']['user_id']
elsif Rails.env.production?
user_id = env['rack.session']['user_id']
end
return nil if user_id.nil?
@current_user ||= User.find(user_id)
end
# Split into two methods: one for authentication, one for authorization
def authorize(api, endpoint, project = nil, projects = nil, global = false)
if current_user.nil? || current_user.anonymous?
raise API::Errors::Unauthenticated.new
end
is_authorized = AuthorizationService.new(api, endpoint, project, projects, global, current_user).perform
unless is_authorized
raise API::Errors::Unauthorized.new(current_user)
end
is_authorized
end
end
rescue_from API::Errors::Validation, API::Errors::UnwritableProperty, API::Errors::Unauthorized,
API::Errors::Unauthenticated do |e|
Rack::Response.new(e.to_json, e.code, e.headers).finish
end
rescue_from ActiveRecord::RecordNotFound do |e|
not_found = API::Errors::NotFound.new(e.message)
Rack::Response.new(not_found.to_json, not_found.code, not_found.headers).finish
end
mount API::V3::Root
end
end

@ -0,0 +1,49 @@
#-- 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.
#++
# Temporarily solution!
# Using customized version of Representable gem (git@github.com:finnlabs/representable.git)
# we can specify strategy to take place during the data serialization
module API
module Utilities
class CamelCasingStrategy
# CamelCase properties of ROAR representer
def call(property)
to_camel_case(property)
end
private
def to_camel_case(string)
return string if string.first == '_'
string.camelize(:lower)
end
end
end
end

@ -0,0 +1,42 @@
#-- 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.
#++
# Root class of the API v3
# This is the place for all API v3 wide configuration, helper methods, exceptions
# rescuing, mounting of differnet API versions etc.
module API
module V3
class Root < Grape::API
version 'v3', using: :path
mount API::V3::WorkPackages::WorkPackagesAPI
end
end
end

@ -0,0 +1,106 @@
#-- 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 'reform/form/coercion'
module API
module V3
module WorkPackages
class WorkPackageModel < Reform::Form
include Composition
include Coercion
model :work_package
property :subject, on: :work_package, type: String
property :description, on: :work_package, type: String
property :start_date, on: :work_package, type: Date
property :due_date, on: :work_package, type: Date
property :created_at, on: :work_package, type: DateTime
property :updated_at, on: :work_package, type: DateTime
property :author, on: :work_package, type: String
property :project_id, on: :work_package, type: Integer
property :responsible_id, on: :work_package, type: Integer
property :assigned_to_id, on: :work_package, type: Integer
property :fixed_version_id, on: :work_package, type: Integer
def type
work_package.type.try(:name)
end
def type=(value)
type = Type.find(:first, conditions: ['name ilike ?', value])
work_package.type = type
end
def status
work_package.status.try(:name)
end
def status=(value)
status = Status.find(:first, conditions: ['name ilike ?', value])
work_package.status = status
end
def priority
work_package.priority.try(:name)
end
def priority=(value)
priority = IssuePriority.find(:first, conditions: ['name ilike ?', value])
work_package.priority = priority
end
def estimated_time
{ units: 'hours', value: work_package.estimated_hours }
end
def estimated_time=(value)
hours = ActiveSupport::JSON.decode(value)['value']
work_package.estimated_hours = hours
end
def version_id=(value)
work_package.fixed_version_id = value
end
def percentage_done
work_package.done_ratio
end
def percentage_done=(value)
work_package.done_ratio = value
end
validates_presence_of :subject, :project_id, :type, :author, :status
validates_length_of :subject, maximum: 255
end
end
end
end

@ -0,0 +1,83 @@
#-- 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 'roar/decorator'
require 'roar/representer/json/hal'
module API
module V3
module WorkPackages
class WorkPackageRepresenter < Roar::Decorator
include Roar::Representer::JSON::HAL
include Roar::Representer::Feature::Hypermedia
include Rails.application.routes.url_helpers
self.as_strategy = API::Utilities::CamelCasingStrategy.new
property :_type, exec_context: :decorator
link :self do
{ href: "http://localhost:3000/api/v3/work_packages/#{represented.work_package.id}", title: "#{represented.subject}" }
end
property :id, getter: -> (*) { work_package.id }, render_nil: true
property :subject, render_nil: true
property :type, render_nil: true
property :description, render_nil: true
property :status, render_nil: true
property :priority, render_nil: true
property :start_date, getter: -> (*) { work_package.start_date }, render_nil: true
property :due_date, getter: -> (*) { work_package.due_date }, render_nil: true
property :estimated_time, render_nil: true
property :percentage_done, render_nil: true
property :version_id, getter: -> (*) { work_package.fixed_version.try(:id) }, render_nil: true
property :version_name, getter: -> (*) { work_package.fixed_version.try(:name) }, render_nil: true
property :project_id, getter: -> (*) { work_package.project.id }
property :project_name, getter: -> (*) { work_package.project.try(:name) }
property :responsible_id, getter: -> (*) { work_package.responsible.try(:id) }, render_nil: true
property :responsible_name, getter: -> (*) { work_package.responsible.try(:name) }, render_nil: true
property :responsible_login, getter: -> (*) { work_package.responsible.try(:login) }, render_nil: true
property :responsible_mail, getter: -> (*) { work_package.responsible.try(:mail) }, render_nil: true
property :assigned_to_id, as: :assigneeId, getter: -> (*) { work_package.assigned_to.try(:id) }, render_nil: true
property :assignee_name, getter: -> (*) { work_package.assigned_to.try(:name) }, render_nil: true
property :assignee_login, getter: -> (*) { work_package.assigned_to.try(:login) }, render_nil: true
property :assignee_mail, getter: -> (*) { work_package.assigned_to.try(:mail) }, render_nil: true
property :author_name, getter: -> (*) { work_package.author.name }, render_nil: true
property :author_login, getter: -> (*) { work_package.author.login }, render_nil: true
property :author_mail, getter: -> (*) { work_package.author.mail }, render_nil: true
property :created_at, getter: -> (*) { work_package.created_at.utc.iso8601}, render_nil: true
property :updated_at, getter: -> (*) { work_package.updated_at.utc.iso8601}, render_nil: true
def _type
"WorkPackage"
end
end
end
end
end

@ -0,0 +1,31 @@
module API
module V3
module WorkPackages
class WorkPackagesAPI < Grape::API
resources :work_packages do
params do
requires :id, desc: 'Work package id'
end
namespace ':id' do
before do
@work_package = WorkPackage.find(params[:id])
model = WorkPackageModel.new(work_package: @work_package)
@representer = WorkPackageRepresenter.new(model)
end
get do
authorize(:work_packages_api, :get, @work_package.project)
@representer.to_json
end
end
end
end
end
end
end

@ -108,6 +108,7 @@ Redmine::AccessControl.map do |map|
:journals => [:index, :diff],
:queries => [:index, :create, :update, :available_columns, :custom_field_filters, :grouped],
:work_packages => [:show, :index],
:work_packages_api => [:get],
:'work_packages/reports' => [:report, :report_details],
:planning_elements => [:index, :all, :show, :recycle_bin],
:planning_element_journals => [:index]}

@ -0,0 +1,121 @@
require 'spec_helper'
require 'rack/test'
describe 'API v3 Work package resource' do
include Rack::Test::Methods
let(:work_package) { FactoryGirl.create(:work_package, :project_id => project.id) }
let(:project) { FactoryGirl.create(:project, :identifier => 'test_project', :is_public => false) }
let(:current_user) { FactoryGirl.create(:user) }
let(:role) { FactoryGirl.create(:role, permissions: [:view_work_packages]) }
let(:unauthorize_user) { FactoryGirl.create(:user) }
let(:type) { FactoryGirl.create(:type) }
describe '#get' do
let(:get_path) { "/api/v3/work_packages/#{work_package.id}" }
let(:expected_response) do
{
"_type" => 'WorkPackage',
"_links" => {
"self" => {
"href" => "http://localhost:3000/api/v3/work_packages/#{work_package.id}",
"title" => work_package.subject
}
},
"id" => work_package.id,
"subject" => work_package.subject,
"type" => work_package.type.name,
"description" => work_package.description,
"status" => work_package.status.name,
"priority" => work_package.priority.name,
"startDate" => work_package.start_date,
"dueDate" => work_package.due_date,
"estimatedTime" => JSON.parse({ units: 'hours', value: work_package.estimated_hours }.to_json),
"percentageDone" => work_package.done_ratio,
"versionId" => work_package.fixed_version_id,
"versionName" => work_package.fixed_version.try(:name),
"projectId" => work_package.project_id,
"projectName" => work_package.project.name,
"responsibleId" => work_package.responsible_id,
"responsibleName" => work_package.responsible.try(:name),
"responsibleLogin" => work_package.responsible.try(:login),
"responsibleMail" => work_package.responsible.try(:mail),
"assigneeId" => work_package.assigned_to_id,
"assigneeName" => work_package.assigned_to.try(:name),
"assigneeLogin" => work_package.assigned_to.try(:login),
"assigneeMail" => work_package.assigned_to.try(:mail),
"authorName" => work_package.author.name,
"authorLogin" => work_package.author.login,
"authorMail" => work_package.author.mail,
"createdAt" => work_package.created_at.utc.iso8601,
"updatedAt" => work_package.updated_at.utc.iso8601
}
end
context 'when acting as a user with permission to view work package' do
before(:each) do
allow(User).to receive(:current).and_return current_user
member = FactoryGirl.build(:member, user: current_user, project: work_package.project)
member.role_ids = [role.id]
member.save!
get get_path
end
it 'should respond with 200' do
last_response.status.should eq(200)
end
it 'should respond with work package in HAL+JSON format' do
parsed_response = JSON.parse(last_response.body)
parsed_response.should eq(expected_response)
end
context 'requesting nonexistent work package' do
let(:get_path) { "/api/v3/work_packages/909090" }
it 'should respond with 404' do
last_response.status.should eq(404)
end
it 'should respond with explanatory error message' do
parsed_errors = JSON.parse(last_response.body)['errors']
parsed_errors.should eq([{ 'key' => 'not_found', 'messages' => ['Couldn\'t find WorkPackage with id=909090']}])
end
end
end
context 'when acting as an user without permission to view work package' do
before(:each) do
allow(User).to receive(:current).and_return unauthorize_user
get get_path
end
it 'should respond with 403' do
last_response.status.should eq(403)
end
it 'should respond with explanatory error message' do
parsed_errors = JSON.parse(last_response.body)['errors']
parsed_errors.should eq([{ 'key' => 'not_authorized', 'messages' => ['You are not authorize to access this resource']}])
end
end
context 'when acting as an anonymous user' do
before(:each) do
allow(User).to receive(:current).and_return User.anonymous
get get_path
end
it 'should respond with 401' do
last_response.status.should eq(401)
end
it 'should respond with explanatory error message' do
parsed_errors = JSON.parse(last_response.body)['errors']
parsed_errors.should eq([{ 'key' => 'not_authenticated', 'messages' => ['You need to be authenticated to access this resource']}])
end
end
end
end

@ -112,6 +112,9 @@ RSpec.configure do |config|
raise "your specs leave a #{cls} in the DB\ndid you use before(:all) instead of before or forget to kill the instances in a after(:all)?" if cls.count > 0
end
end
# include spec/api for API request specs
config.include RSpec::Rails::RequestExampleGroup, type: :request, example_group: { file_path: /spec\/api/ }
end
# load disable_specs.rbs from plugins

Loading…
Cancel
Save