From 95deb6a984d4a30d1fc51ce5d78719ce75011b34 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 7 Nov 2022 12:23:54 +0100 Subject: [PATCH 01/46] add gem, basic setup --- Gemfile | 3 ++ Gemfile.lock | 13 ++++++ config/initializers/rswag_api.rb | 14 ++++++ config/initializers/rswag_ui.rb | 16 +++++++ config/routes.rb | 2 + spec/requests/api/users_spec.rb | 22 ++++++++++ spec/swagger_helper.rb | 73 ++++++++++++++++++++++++++++++++ swagger/v1/swagger.yaml | 43 +++++++++++++++++++ 8 files changed, 186 insertions(+) create mode 100644 config/initializers/rswag_api.rb create mode 100644 config/initializers/rswag_ui.rb create mode 100644 spec/requests/api/users_spec.rb create mode 100644 spec/swagger_helper.rb create mode 100644 swagger/v1/swagger.yaml diff --git a/Gemfile b/Gemfile index a6e27fae..ee78ee85 100644 --- a/Gemfile +++ b/Gemfile @@ -55,6 +55,8 @@ gem 'gaffe' gem 'ruby-filemagic' gem 'mime-types' gem 'midi-smtp-server' +gem 'rswag-api' +gem 'rswag-ui' # we use the git version of acts_as_versioned, and need to include it in this Gemfile gem 'acts_as_versioned', git: 'https://github.com/technoweenie/acts_as_versioned.git' @@ -118,4 +120,5 @@ group :test do # api gem 'apivore', require: false gem 'hashie', '~> 3.4.6', require: false # https://github.com/westfieldlabs/apivore/issues/114 + gem 'rswag-specs' end diff --git a/Gemfile.lock b/Gemfile.lock index c53687fb..7f5e5912 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -430,6 +430,16 @@ GEM rspec-rerun (1.1.0) rspec (~> 3.0) rspec-support (3.11.1) + rswag-api (2.7.0) + railties (>= 3.1, < 7.1) + rswag-specs (2.7.0) + activesupport (>= 3.1, < 7.1) + json-schema (>= 2.2, < 4.0) + railties (>= 3.1, < 7.1) + rspec-core (>= 2.14) + rswag-ui (2.7.0) + actionpack (>= 3.1, < 7.1) + railties (>= 3.1, < 7.1) rubocop (1.36.0) json (~> 2.3) parallel (~> 1.10) @@ -617,6 +627,9 @@ DEPENDENCIES rspec-core rspec-rails rspec-rerun + rswag-api + rswag-specs + rswag-ui rubocop rubocop-rails rubocop-rspec diff --git a/config/initializers/rswag_api.rb b/config/initializers/rswag_api.rb new file mode 100644 index 00000000..4d72f687 --- /dev/null +++ b/config/initializers/rswag_api.rb @@ -0,0 +1,14 @@ +Rswag::Api.configure do |c| + + # Specify a root folder where Swagger JSON files are located + # This is used by the Swagger middleware to serve requests for API descriptions + # NOTE: If you're using rswag-specs to generate Swagger, you'll need to ensure + # that it's configured to generate files in the same folder + c.swagger_root = Rails.root.to_s + '/swagger' + + # Inject a lambda function to alter the returned Swagger prior to serialization + # The function will have access to the rack env for the current request + # For example, you could leverage this to dynamically assign the "host" property + # + #c.swagger_filter = lambda { |swagger, env| swagger['host'] = env['HTTP_HOST'] } +end diff --git a/config/initializers/rswag_ui.rb b/config/initializers/rswag_ui.rb new file mode 100644 index 00000000..0a768c17 --- /dev/null +++ b/config/initializers/rswag_ui.rb @@ -0,0 +1,16 @@ +Rswag::Ui.configure do |c| + + # List the Swagger endpoints that you want to be documented through the + # swagger-ui. The first parameter is the path (absolute or relative to the UI + # host) to the corresponding endpoint and the second is a title that will be + # displayed in the document selector. + # NOTE: If you're using rspec-api to expose Swagger files + # (under swagger_root) as JSON or YAML endpoints, then the list below should + # correspond to the relative paths for those endpoints. + + c.swagger_endpoint '/api-docs/v1/swagger.yaml', 'API V1 Docs' + + # Add Basic Auth in case your API is private + # c.basic_auth_enabled = true + # c.basic_auth_credentials 'username', 'password' +end diff --git a/config/routes.rb b/config/routes.rb index 5b27eba4..83e65707 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,6 @@ Rails.application.routes.draw do + mount Rswag::Ui::Engine => '/api-docs' + mount Rswag::Api::Engine => '/api-docs' get "order_comments/new" get "comments/new" diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb new file mode 100644 index 00000000..8e1e23fb --- /dev/null +++ b/spec/requests/api/users_spec.rb @@ -0,0 +1,22 @@ +require 'swagger_helper' + +describe 'Users API', type: :request do + path '/user' do + get 'info about the currently logged-in user' do + tags '1. User' + produces 'application/json' + + response '200', 'success' do + run_test! do |response| + let(:Authorization) { "Basic #{::Base64.strict_encode64('jsmith:jspass')}" } + data = JSON.parse(response.body) + # expect(data[]) + end + end + + response '401', 'not logged-in' do + run_test! + end + end + end +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb new file mode 100644 index 00000000..0cfa8370 --- /dev/null +++ b/spec/swagger_helper.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.configure do |config| + # Specify a root folder where Swagger JSON files are generated + # NOTE: If you're using the rswag-api to serve API descriptions, you'll need + # to ensure that it's configured to serve Swagger from the same folder + config.swagger_root = Rails.root.join('swagger').to_s + + # Define one or more Swagger documents and provide global metadata for each one + # When you run the 'rswag:specs:swaggerize' rake task, the complete Swagger will + # be generated at the provided relative path under swagger_root + # By default, the operations defined in spec files are added to the first + # document below. You can override this behavior by adding a swagger_doc tag to the + # the root example_group in your specs, e.g. describe '...', swagger_doc: 'v2/swagger.json' + config.swagger_docs = { + 'v1/swagger.yaml' => { + openapi: '3.0.1', + info: { + title: 'API V1', + version: 'v1' + }, + paths: {}, + components: { + securitySchemes: { + oauth2: { + type: :oauth2, + in: :header, + name: 'Authorization', + flows: { + implicit: { + authorizationUrl: 'http://localhost:3000/f/oauth/authorize', + scopes: { + 'config:user': 'reading Foodsoft configuration for regular users', + 'config:read': 'reading Foodsoft configuration values', + 'config:write': 'reading and updating Foodsoft configuration values', + 'finance:user': 'accessing your own financial transactions', + 'finance:read': 'reading all financial transactions', + 'finance:write': 'reading and creating financial transactions', + 'user:read': 'reading your own user profile', + 'user:write': 'reading and updating your own user profile', + offline_access: 'retain access after user has logged out', + } + } + } + } + } + }, + servers: [ + { + url: 'http://{defaultHost}/f/api/v1', + variables: { + defaultHost: { + default: 'localhost:3000' + } + } + } + ], + security: [ + oauth2: [ + 'user:read', + ], + ], + } + } + + # Specify the format of the output Swagger file when running 'rswag:specs:swaggerize'. + # The swagger_docs configuration option has the filename including format in + # the key, this may want to be changed to avoid putting yaml in json files. + # Defaults to json. Accepts ':json' and ':yaml'. + config.swagger_format = :yaml +end diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml new file mode 100644 index 00000000..549db1d2 --- /dev/null +++ b/swagger/v1/swagger.yaml @@ -0,0 +1,43 @@ +--- +openapi: 3.0.1 +info: + title: API V1 + version: v1 +paths: + "/user": + get: + summary: info about the currently logged-in user + tags: + - 1. User + responses: + '200': + description: success + '401': + description: not logged-in +components: + securitySchemes: + oauth2: + type: oauth2 + in: header + name: Authorization + flows: + implicit: + authorizationUrl: http://localhost:3000/f/oauth/authorize + scopes: + config:user: reading Foodsoft configuration for regular users + config:read: reading Foodsoft configuration values + config:write: reading and updating Foodsoft configuration values + finance:user: accessing your own financial transactions + finance:read: reading all financial transactions + finance:write: reading and creating financial transactions + user:read: reading your own user profile + user:write: reading and updating your own user profile + offline_access: retain access after user has logged out +servers: +- url: http://{defaultHost}/f/api/v1 + variables: + defaultHost: + default: localhost:3000 +security: +- oauth2: + - user:read -- 2.45.2 From df3a2c0c48780399eecc1c14aca460fd52e21754 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 7 Nov 2022 13:41:39 +0100 Subject: [PATCH 02/46] add authorization to tests --- spec/requests/api/users_spec.rb | 15 +++++++++++++-- spec/support/factory_bot.rb | 2 +- spec/swagger_helper.rb | 2 -- swagger/v1/swagger.yaml | 4 ++-- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 8e1e23fb..25e0eb55 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -3,18 +3,29 @@ require 'swagger_helper' describe 'Users API', type: :request do path '/user' do get 'info about the currently logged-in user' do + # security [oauth2: []] tags '1. User' produces 'application/json' + let(:user) { create(:user) } + let(:api_access_token) { create(:oauth2_access_token, resource_owner_id: user.id, scopes: api_scopes&.join(' ')).token } + let(:Authorization) { "Bearer #{api_access_token}" } response '200', 'success' do + let(:api_scopes) { ['user:read'] } run_test! do |response| - let(:Authorization) { "Basic #{::Base64.strict_encode64('jsmith:jspass')}" } data = JSON.parse(response.body) - # expect(data[]) + expect(data['user']['id']).to eq(user.id) end end + response '403', 'missing scope' do + let(:api_scopes) { [] } + run_test! + end + + response '401', 'not logged-in' do + let(:Authorization) { "" } run_test! end end diff --git a/spec/support/factory_bot.rb b/spec/support/factory_bot.rb index 655548ee..2cb72940 100644 --- a/spec/support/factory_bot.rb +++ b/spec/support/factory_bot.rb @@ -1,4 +1,4 @@ RSpec.configure do |config| # load FactoryBot shortcuts create(), etc. config.include FactoryBot::Syntax::Methods -end +end \ No newline at end of file diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 0cfa8370..88f0736f 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -26,8 +26,6 @@ RSpec.configure do |config| securitySchemes: { oauth2: { type: :oauth2, - in: :header, - name: 'Authorization', flows: { implicit: { authorizationUrl: 'http://localhost:3000/f/oauth/authorize', diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index 549db1d2..7702e953 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -12,14 +12,14 @@ paths: responses: '200': description: success + '403': + description: missing scope '401': description: not logged-in components: securitySchemes: oauth2: type: oauth2 - in: header - name: Authorization flows: implicit: authorizationUrl: http://localhost:3000/f/oauth/authorize -- 2.45.2 From dbab0ef12bdfd960889e67f2ab192d1532d73638 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 7 Nov 2022 17:42:32 +0100 Subject: [PATCH 03/46] refactor invalid token, scope --- spec/api/v1/swagger_spec.rb | 68 ++++++++++++++++----------------- spec/requests/api/users_spec.rb | 32 +++++++++------- spec/support/api_helper.rb | 24 +++++++----- swagger/v1/swagger.yaml | 19 +++++++-- 4 files changed, 84 insertions(+), 59 deletions(-) diff --git a/spec/api/v1/swagger_spec.rb b/spec/api/v1/swagger_spec.rb index 3da37332..5202af83 100644 --- a/spec/api/v1/swagger_spec.rb +++ b/spec/api/v1/swagger_spec.rb @@ -8,24 +8,24 @@ class SwaggerCheckerFile < Apivore::SwaggerChecker end end -describe 'API v1', type: :apivore, order: :defined do +describe 'API v1', :skip, type: :apivore, order: :defined do include ApiHelper subject { SwaggerCheckerFile.instance_for Rails.root.join('doc', 'swagger.v1.yml') } context 'has valid paths' do - context 'user' do - let(:api_scopes) { ['user:read'] } - # create multiple users to make sure we're getting the authenticated user, not just any - let!(:other_user_1) { create :user } - let!(:user) { create :user } - let!(:other_user_2) { create :user } + # context 'user' do + # let(:api_scopes) { ['user:read'] } + # # create multiple users to make sure we're getting the authenticated user, not just any + # let!(:other_user_1) { create :user } + # let!(:user) { create :user } + # let!(:other_user_2) { create :user } - it { is_expected.to validate(:get, '/user', 200, api_auth) } - it { is_expected.to validate(:get, '/user', 401) } + # it { is_expected.to validate(:get, '/user', 200, api_auth) } + # it { is_expected.to validate(:get, '/user', 401) } - it_handles_invalid_token_and_scope(:get, '/user') - end + # # it_handles_invalid_token_and_scope(:get, '/user') + # end context 'user/financial_overview' do let(:api_scopes) { ['finance:user'] } @@ -34,7 +34,7 @@ describe 'API v1', type: :apivore, order: :defined do it { is_expected.to validate(:get, '/user/financial_overview', 200, api_auth) } it { is_expected.to validate(:get, '/user/financial_overview', 401) } - it_handles_invalid_token_and_scope(:get, '/user/financial_overview') + # it_handles_invalid_token_and_scope(:get, '/user/financial_overview') end context 'user/financial_transactions' do @@ -88,9 +88,9 @@ describe 'API v1', type: :apivore, order: :defined do end end - it_handles_invalid_token_and_scope(:get, '/user/financial_transactions') - it_handles_invalid_token_and_scope(:post, '/user/financial_transactions', -> { api_auth(create_params) }) - it_handles_invalid_token_and_scope(:get, '/user/financial_transactions/{id}', -> { api_auth('id' => ft_2.id) }) + # it_handles_invalid_token_and_scope(:get, '/user/financial_transactions') + # it_handles_invalid_token_and_scope(:post, '/user/financial_transactions', -> { api_auth(create_params) }) + # it_handles_invalid_token_and_scope(:get, '/user/financial_transactions/{id}', -> { api_auth('id' => ft_2.id) }) end end @@ -165,11 +165,11 @@ describe 'API v1', type: :apivore, order: :defined do it { is_expected.to validate(:delete, '/user/group_order_articles/{id}', 200, api_auth({ 'id' => goa.id })) } end - it_handles_invalid_token_and_scope(:get, '/user/group_order_articles') - it_handles_invalid_token_and_scope(:post, '/user/group_order_articles', -> { api_auth(create_params) }) - it_handles_invalid_token_and_scope(:get, '/user/group_order_articles/{id}', -> { api_auth({ 'id' => goa.id }) }) - it_handles_invalid_token_and_scope(:patch, '/user/group_order_articles/{id}', -> { api_auth(update_params) }) - it_handles_invalid_token_and_scope(:delete, '/user/group_order_articles/{id}', -> { api_auth({ 'id' => goa.id }) }) + # it_handles_invalid_token_and_scope(:get, '/user/group_order_articles') + # it_handles_invalid_token_and_scope(:post, '/user/group_order_articles', -> { api_auth(create_params) }) + # it_handles_invalid_token_and_scope(:get, '/user/group_order_articles/{id}', -> { api_auth({ 'id' => goa.id }) }) + # it_handles_invalid_token_and_scope(:patch, '/user/group_order_articles/{id}', -> { api_auth(update_params) }) + # it_handles_invalid_token_and_scope(:delete, '/user/group_order_articles/{id}', -> { api_auth({ 'id' => goa.id }) }) end end @@ -179,14 +179,14 @@ describe 'API v1', type: :apivore, order: :defined do it { is_expected.to validate(:get, '/config', 200, api_auth) } it { is_expected.to validate(:get, '/config', 401) } - it_handles_invalid_token_and_scope(:get, '/config') + # it_handles_invalid_token_and_scope(:get, '/config') end context 'navigation' do it { is_expected.to validate(:get, '/navigation', 200, api_auth) } it { is_expected.to validate(:get, '/navigation', 401) } - it_handles_invalid_token(:get, '/navigation') + # #it_handles_invalid_token(:get, '/navigation') end context 'financial_transactions' do @@ -207,8 +207,8 @@ describe 'API v1', type: :apivore, order: :defined do it { is_expected.to validate(:get, '/financial_transactions/{id}', 403, api_auth({ 'id' => ft_2.id })) } end - it_handles_invalid_token_and_scope(:get, '/financial_transactions') - it_handles_invalid_token_and_scope(:get, '/financial_transactions/{id}', -> { api_auth({ 'id' => ft_2.id }) }) + # it_handles_invalid_token_and_scope(:get, '/financial_transactions') + # it_handles_invalid_token_and_scope(:get, '/financial_transactions/{id}', -> { api_auth({ 'id' => ft_2.id }) }) end context 'financial_transaction_classes' do @@ -219,8 +219,8 @@ describe 'API v1', type: :apivore, order: :defined do it { is_expected.to validate(:get, '/financial_transaction_classes/{id}', 200, api_auth({ 'id' => cla_2.id })) } it { is_expected.to validate(:get, '/financial_transaction_classes/{id}', 404, api_auth({ 'id' => cla_2.id + 1 })) } - it_handles_invalid_token(:get, '/financial_transaction_classes') - it_handles_invalid_token(:get, '/financial_transaction_classes/{id}', -> { api_auth({ 'id' => cla_1.id }) }) + #it_handles_invalid_token(:get, '/financial_transaction_classes') + #it_handles_invalid_token(:get, '/financial_transaction_classes/{id}', -> { api_auth({ 'id' => cla_1.id }) }) end context 'financial_transaction_types' do @@ -231,8 +231,8 @@ describe 'API v1', type: :apivore, order: :defined do it { is_expected.to validate(:get, '/financial_transaction_types/{id}', 200, api_auth({ 'id' => tpy_2.id })) } it { is_expected.to validate(:get, '/financial_transaction_types/{id}', 404, api_auth({ 'id' => tpy_2.id + 1 })) } - it_handles_invalid_token(:get, '/financial_transaction_types') - it_handles_invalid_token(:get, '/financial_transaction_types/{id}', -> { api_auth({ 'id' => tpy_1.id }) }) + ##it_handles_invalid_token(:get, '/financial_transaction_types') + ##it_handles_invalid_token(:get, '/financial_transaction_types/{id}', -> { api_auth({ 'id' => tpy_1.id }) }) end context 'orders' do @@ -243,8 +243,8 @@ describe 'API v1', type: :apivore, order: :defined do it { is_expected.to validate(:get, '/orders/{id}', 200, api_auth({ 'id' => order.id })) } it { is_expected.to validate(:get, '/orders/{id}', 404, api_auth({ 'id' => Order.last.id + 1 })) } - it_handles_invalid_token_and_scope(:get, '/orders') - it_handles_invalid_token_and_scope(:get, '/orders/{id}', -> { api_auth({ 'id' => order.id }) }) + # #it_handles_invalid_token_and_scope(:get, '/orders') + # #it_handles_invalid_token_and_scope(:get, '/orders/{id}', -> { api_auth({ 'id' => order.id }) }) end context 'order_articles' do @@ -258,8 +258,8 @@ describe 'API v1', type: :apivore, order: :defined do it { is_expected.to validate(:get, '/order_articles/{id}', 200, api_auth({ 'id' => stock_order_article.id })) } it { is_expected.to validate(:get, '/order_articles/{id}', 404, api_auth({ 'id' => Article.last.id + 1 })) } - it_handles_invalid_token_and_scope(:get, '/order_articles') - it_handles_invalid_token_and_scope(:get, '/order_articles/{id}', -> { api_auth({ 'id' => order_article.id }) }) + # it_handles_invalid_token_and_scope(:get, '/order_articles') + # it_handles_invalid_token_and_scope(:get, '/order_articles/{id}', -> { api_auth({ 'id' => order_article.id }) }) end context 'article_categories' do @@ -270,8 +270,8 @@ describe 'API v1', type: :apivore, order: :defined do it { is_expected.to validate(:get, '/article_categories/{id}', 200, api_auth({ 'id' => cat_2.id })) } it { is_expected.to validate(:get, '/article_categories/{id}', 404, api_auth({ 'id' => cat_2.id + 1 })) } - it_handles_invalid_token(:get, '/article_categories') - it_handles_invalid_token(:get, '/article_categories/{id}', -> { api_auth({ 'id' => cat_1.id }) }) + #it_handles_invalid_token(:get, '/article_categories') + #it_handles_invalid_token(:get, '/article_categories/{id}', -> { api_auth({ 'id' => cat_1.id }) }) end end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 25e0eb55..d6542fc3 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -1,33 +1,39 @@ require 'swagger_helper' describe 'Users API', type: :request do + include ApiHelper + path '/user' do get 'info about the currently logged-in user' do - # security [oauth2: []] - tags '1. User' + tags 'User' produces 'application/json' - let(:user) { create(:user) } - let(:api_access_token) { create(:oauth2_access_token, resource_owner_id: user.id, scopes: api_scopes&.join(' ')).token } - let(:Authorization) { "Bearer #{api_access_token}" } + let(:api_scopes) { ['user:read'] } + let(:other_user_1) { create :user } + let(:user) { create :user } + let(:other_user_2) { create :user } response '200', 'success' do - let(:api_scopes) { ['user:read'] } run_test! do |response| data = JSON.parse(response.body) expect(data['user']['id']).to eq(user.id) end end - response '403', 'missing scope' do - let(:api_scopes) { [] } + it_handles_invalid_token_and_scope + end + end + + path '/user/financial_overview' do + get 'financial summary about the currently logged-in user' do + tags 'User', 'FinancialTransaction' + let!(:user) { create :user, :ordergroup } + + response 200, 'success' do + let(:api_scopes) { ['finance:user'] } run_test! end - - response '401', 'not logged-in' do - let(:Authorization) { "" } - run_test! - end + it_handles_invalid_token_and_scope end end end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index ee0225f5..504c59c8 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -5,21 +5,26 @@ module ApiHelper let(:user) { create(:user) } let(:api_scopes) { [] } # empty scopes for stricter testing (in reality this would be default_scopes) let(:api_access_token) { create(:oauth2_access_token, resource_owner_id: user.id, scopes: api_scopes&.join(' ')).token } - let(:api_authorization) { "Bearer #{api_access_token}" } + let(:Authorization) { "Bearer #{api_access_token}" } - def self.it_handles_invalid_token(method, path, params_block = -> { api_auth }) + # TODO: not needed anymore? + def self.it_handles_invalid_token() context 'with invalid access token' do - let(:api_access_token) { 'abc' } + let(:Authorization) { 'abc' } - it { is_expected.to validate(method, path, 401, instance_exec(¶ms_block)) } + response 401, 'not logged-in' do + run_test! + end end end - def self.it_handles_invalid_scope(method, path, params_block = -> { api_auth }) + def self.it_handles_invalid_scope() context 'with invalid scope' do let(:api_scopes) { ['none'] } - it { is_expected.to validate(method, path, 403, instance_exec(¶ms_block)) } + response 403, 'missing scope' do + run_test! + end end end @@ -33,7 +38,8 @@ module ApiHelper # @param params [Hash] Query parameters # @return Query parameters with authentication header # @see Swagger::RspecHelpers#validate - def api_auth(params = {}) - { '_headers' => { 'Authorization' => api_authorization } }.deep_merge(params) - end + # def api_auth(params = {}) + # { '_headers' => { 'Authorization' => api_authorization } }.deep_merge(params) + # end + # TODO: not needed anymore end diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index 7702e953..cba34f7e 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -8,14 +8,27 @@ paths: get: summary: info about the currently logged-in user tags: - - 1. User + - User responses: '200': description: success - '403': - description: missing scope '401': description: not logged-in + '403': + description: missing scope + "/user/financial_overview": + get: + summary: financial summary about the currently logged-in user + tags: + - User + - FinancialTransaction + responses: + '200': + description: success + '401': + description: not logged-in + '403': + description: missing scope components: securitySchemes: oauth2: -- 2.45.2 From f5995781b16b9ac1eab099f4dfa3750d20c2f4f8 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 7 Nov 2022 17:49:28 +0100 Subject: [PATCH 04/46] remove apivore --- Gemfile | 2 -- Gemfile.lock | 8 -------- 2 files changed, 10 deletions(-) diff --git a/Gemfile b/Gemfile index ee78ee85..4ff617d8 100644 --- a/Gemfile +++ b/Gemfile @@ -118,7 +118,5 @@ group :test do gem 'simplecov', require: false gem 'simplecov-lcov', require: false # api - gem 'apivore', require: false - gem 'hashie', '~> 3.4.6', require: false # https://github.com/westfieldlabs/apivore/issues/114 gem 'rswag-specs' end diff --git a/Gemfile.lock b/Gemfile.lock index 7f5e5912..d86fc580 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,13 +109,6 @@ GEM activerecord (>= 3.0.0) addressable (2.8.1) public_suffix (>= 2.0.2, < 6.0) - apivore (1.6.2) - actionpack (>= 4, < 6) - hashie (~> 3.3) - json-schema (~> 2.5) - rspec (~> 3) - rspec-expectations (~> 3.1) - rspec-mocks (~> 3.1) apparition (0.6.0) capybara (~> 3.13, < 4) websocket-driver (>= 0.6.5) @@ -567,7 +560,6 @@ DEPENDENCIES active_model_serializers (~> 0.10.0) acts_as_tree acts_as_versioned! - apivore apparition attribute_normalizer better_errors -- 2.45.2 From 614aef746fb4c839cfadb3982ffda8818a2bafd5 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 21 Nov 2022 12:49:53 +0100 Subject: [PATCH 05/46] add schemas --- doc/API.md | 6 +- spec/requests/api/user_spec.rb | 96 +++++++++++++++++++++++++++ spec/requests/api/users_spec.rb | 39 ----------- spec/support/api_helper.rb | 12 +--- spec/swagger_helper.rb | 63 ++++++++++++++++++ swagger/v1/swagger.yaml | 113 ++++++++++++++++++++++++++++++++ 6 files changed, 278 insertions(+), 51 deletions(-) create mode 100644 spec/requests/api/user_spec.rb delete mode 100644 spec/requests/api/users_spec.rb diff --git a/doc/API.md b/doc/API.md index 2e09cfa4..f295e82f 100644 --- a/doc/API.md +++ b/doc/API.md @@ -5,9 +5,11 @@ like listing open orders, updating the ordergroup's order, and listing financial transactions. Not all Foodsoft functionality is available through the API, but we're open for new additions. -The API is documented using [Open API 2.0](https://github.com/OAI/OpenAPI-Specification) -/ [Swagger](https://swagger.io/) in [swagger.v1.yml](swagger.v1.yml). +The API is documented using [Open API 3.0.1](https://github.com/OAI/OpenAPI-Specification) +/ [Swagger](https://swagger.io/) in [swagger.yaml](/swagger/v1/swagger.yaml). This provides a machine-readable reference that is used to provide documentation. +It is generated by [rswag](https://github.com/rswag) wich also provides api-tests. +It can be generated running `RAILS_ENV=test rails rswag`. **Note:** the current OAuth scopes may be subject to change, until the next release of Foodsoft. diff --git a/spec/requests/api/user_spec.rb b/spec/requests/api/user_spec.rb new file mode 100644 index 00000000..ed002ba1 --- /dev/null +++ b/spec/requests/api/user_spec.rb @@ -0,0 +1,96 @@ +require 'swagger_helper' + +describe 'User API', type: :request do + include ApiHelper + + path '/user' do + get 'info about the currently logged-in user' do + tags 'User' + produces 'application/json' + let(:api_scopes) { ['user:read'] } + let(:other_user1) { create :user } + let(:user) { create :user } + let(:other_user2) { create :user } + + response '200', 'success' do + schema type: :object, + properties: { + user: { + type: :object, + properties: { + id: { + type: :integer + }, + name: { + type: :string, + description: 'full name' + }, + email: { + type: :string, + description: 'email address' + }, + locale: { + type: :string, + description: 'language code' + } + }, + required: %w[id name email] + } + } + + run_test! do |response| + data = JSON.parse(response.body) + expect(data['user']['id']).to eq(user.id) + end + end + + it_handles_invalid_token_and_scope + end + end + + path '/user/financial_overview' do + get 'financial summary about the currently logged-in user' do + tags 'User', 'FinancialTransaction' + produces 'application/json' + let!(:user) { create :user, :ordergroup } + + response 200, 'success' do + schema type: :object, + properties: { + account_balance: { + type: :number, + description: 'booked accout balance of ordergroup' + }, + available_funds: { + type: :number, + description: 'fund available to order articles' + }, + financial_transaction_class_sums: { + type: :object, + properties: { + id: { + type: :integer, + description: 'id of the financial transaction class' + }, + name: { + type: :string, + description: 'name of the financial transaction class' + }, + amount: { + type: :number, + description: 'sum of the amounts belonging to the financial transaction class' + }, + required: %w[id name amount] + }, + required: %w[account_balance available_funds financial_transaction_class_sums] + } + } + + let(:api_scopes) { ['finance:user'] } + run_test! + end + + it_handles_invalid_token_and_scope + end + end +end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb deleted file mode 100644 index d6542fc3..00000000 --- a/spec/requests/api/users_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -require 'swagger_helper' - -describe 'Users API', type: :request do - include ApiHelper - - path '/user' do - get 'info about the currently logged-in user' do - tags 'User' - produces 'application/json' - let(:api_scopes) { ['user:read'] } - let(:other_user_1) { create :user } - let(:user) { create :user } - let(:other_user_2) { create :user } - - response '200', 'success' do - run_test! do |response| - data = JSON.parse(response.body) - expect(data['user']['id']).to eq(user.id) - end - end - - it_handles_invalid_token_and_scope - end - end - - path '/user/financial_overview' do - get 'financial summary about the currently logged-in user' do - tags 'User', 'FinancialTransaction' - let!(:user) { create :user, :ordergroup } - - response 200, 'success' do - let(:api_scopes) { ['finance:user'] } - run_test! - end - - it_handles_invalid_token_and_scope - end - end -end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 504c59c8..c5357e7d 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -7,12 +7,12 @@ module ApiHelper let(:api_access_token) { create(:oauth2_access_token, resource_owner_id: user.id, scopes: api_scopes&.join(' ')).token } let(:Authorization) { "Bearer #{api_access_token}" } - # TODO: not needed anymore? def self.it_handles_invalid_token() context 'with invalid access token' do let(:Authorization) { 'abc' } response 401, 'not logged-in' do + schema '$ref' => '#/components/schemas/Error401' run_test! end end @@ -23,6 +23,7 @@ module ApiHelper let(:api_scopes) { ['none'] } response 403, 'missing scope' do + schema '$ref' => '#/components/schemas/Error403' run_test! end end @@ -33,13 +34,4 @@ module ApiHelper it_handles_invalid_scope(*args) end end - - # Add authentication to parameters for {Swagger::RspecHelpers#validate} - # @param params [Hash] Query parameters - # @return Query parameters with authentication header - # @see Swagger::RspecHelpers#validate - # def api_auth(params = {}) - # { '_headers' => { 'Authorization' => api_authorization } }.deep_merge(params) - # end - # TODO: not needed anymore end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 88f0736f..c45fd0af 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -23,6 +23,69 @@ RSpec.configure do |config| }, paths: {}, components: { + schemas: { + Error: { + type: :object, + properties: { + error: { + type: :string, + description: 'error code' + }, + error_description: { + type: :string, + description: 'human-readable error message (localized)' + } + } + }, + Error401: { + type: :object, + properties: { + error: { + type: :string, + description: 'unauthorized' + }, + error_description: { + '$ref': '#/components/schemas/Error/properties/error_description' + } + } + }, + Error403: { + type: :object, + properties: { + error: { + type: :string, + description: 'forbidden or invalid_scope' + }, + error_description: { + '$ref': '#/components/schemas/Error/properties/error_description' + } + } + }, + Error404: { + type: :object, + properties: { + error: { + type: :string, + description: 'not_found' + }, + error_description: { + '$ref': '#/components/schemas/Error/properties/error_description' + } + } + }, + Error422: { + type: :object, + properties: { + error: { + type: :string, + description: 'unprocessable entity' + }, + error_description: { + '$ref': '#/components/schemas/Error/properties/error_description' + } + } + } + }, securitySchemes: { oauth2: { type: :oauth2, diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index cba34f7e..5fe3a5a3 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -12,10 +12,41 @@ paths: responses: '200': description: success + content: + application/json: + schema: + type: object + properties: + user: + type: object + properties: + id: + type: integer + name: + type: string + description: full name + email: + type: string + description: email address + locale: + type: string + description: language code + required: + - id + - name + - email '401': description: not logged-in + content: + application/json: + schema: + "$ref": "#/components/schemas/Error401" '403': description: missing scope + content: + application/json: + schema: + "$ref": "#/components/schemas/Error403" "/user/financial_overview": get: summary: financial summary about the currently logged-in user @@ -25,11 +56,93 @@ paths: responses: '200': description: success + content: + application/json: + schema: + type: object + properties: + account_balance: + type: number + description: booked accout balance of ordergroup + available_funds: + type: number + description: fund available to order articles + financial_transaction_class_sums: + type: object + properties: + id: + type: integer + description: id of the financial transaction class + name: + type: string + description: name of the financial transaction class + amount: + type: number + description: sum of the amounts belonging to the financial + transaction class + required: + - id + - name + - amount + required: + - account_balance + - available_funds + - financial_transaction_class_sums '401': description: not logged-in + content: + application/json: + schema: + "$ref": "#/components/schemas/Error401" '403': description: missing scope + content: + application/json: + schema: + "$ref": "#/components/schemas/Error403" components: + schemas: + Error: + type: object + properties: + error: + type: string + description: error code + error_description: + type: string + description: human-readable error message (localized) + Error401: + type: object + properties: + error: + type: string + description: "unauthorized" + error_description: + "$ref": "#/components/schemas/Error/properties/error_description" + Error403: + type: object + properties: + error: + type: string + description: "forbidden or invalid_scope" + error_description: + "$ref": "#/components/schemas/Error/properties/error_description" + Error404: + type: object + properties: + error: + type: string + description: "not_found" + error_description: + "$ref": "#/components/schemas/Error/properties/error_description" + Error422: + type: object + properties: + error: + type: string + description: unprocessable entity + error_description: + "$ref": "#/components/schemas/Error/properties/error_description" securitySchemes: oauth2: type: oauth2 -- 2.45.2 From 78bb7c67e8e1f8b6a93cc3ed446806d12971188c Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 21 Nov 2022 12:52:29 +0100 Subject: [PATCH 06/46] remove old api tests --- doc/swagger.v1.yml | 1106 ----------------- spec/api/v1/order_articles_spec.rb | 59 - spec/api/v1/swagger_spec.rb | 284 ----- .../v1/user/financial_transactions_spec.rb | 109 -- spec/api/v1/user/group_order_articles_spec.rb | 220 ---- spec/api/v1/user/ordergroup_spec.rb | 55 - 6 files changed, 1833 deletions(-) delete mode 100644 doc/swagger.v1.yml delete mode 100644 spec/api/v1/order_articles_spec.rb delete mode 100644 spec/api/v1/swagger_spec.rb delete mode 100644 spec/api/v1/user/financial_transactions_spec.rb delete mode 100644 spec/api/v1/user/group_order_articles_spec.rb delete mode 100644 spec/api/v1/user/ordergroup_spec.rb diff --git a/doc/swagger.v1.yml b/doc/swagger.v1.yml deleted file mode 100644 index d8e793d3..00000000 --- a/doc/swagger.v1.yml +++ /dev/null @@ -1,1106 +0,0 @@ -swagger: '2.0' -info: - title: Foodsoft API v1 - version: '1.0.0' - description: > - [Foodsoft](https://github.com/foodcoops/foodsoft) is web-based software to manage - a non-profit food coop (product catalog, ordering, accounting, job scheduling). - - - This is a description of Foodsoft's API v1. - - - Note that each food cooperative typically has their own instance (on a shared - server or their own installation), and there are just as many APIs (if the Foodsoft - version is recent enough). - This API description points to the default development url with the default - Foodsoft scope - that would be [http://localhost:3000/f](http://localhost:3000/f). - - You may find the search parameters for index endpoints lacking. They are not - documented here, because there are too many combinations. For now, you'll need - to resort to [Ransack](https://github.com/activerecord-hackery/ransack) and - looking at Foodsoft's `ransackable_*` model class methods. -externalDocs: - description: General Foodsoft API documentation - url: https://github.com/foodcoops/foodsoft/blob/master/doc/API.md - -# development url with default scope -host: localhost:3000 -schemes: - - 'http' -basePath: /f/api/v1 - -produces: - - 'application/json' - -paths: - /user: - get: - summary: info about the currently logged-in user - tags: - - 1. User - responses: - 200: - description: success - schema: - type: object - properties: - user: - $ref: '#/definitions/User' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: missing scope - schema: - $ref: '#/definitions/Error403' - security: - - foodsoft_auth: ['user:read', 'user:write'] - - /user/financial_overview: - get: - summary: financial summary about the currently logged-in user - tags: - - 1. User - - 6. FinancialTransaction - responses: - 200: - description: success - schema: - type: object - properties: - financial_overview: - $ref: '#/definitions/FinanceOverview' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: missing scope - schema: - $ref: '#/definitions/Error403' - security: - - foodsoft_auth: ['finance:user'] - - /user/financial_transactions: - get: - summary: financial transactions of the member's ordergroup - tags: - - 1. User - - 6. FinancialTransaction - parameters: - - $ref: '#/parameters/page' - - $ref: '#/parameters/per_page' - responses: - 200: - description: success - schema: - type: object - properties: - financial_transactions: - type: array - items: - $ref: '#/definitions/FinancialTransaction' - meta: - $ref: '#/definitions/Meta' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: user has no ordergroup or missing scope - schema: - $ref: '#/definitions/Error403' - security: - - foodsoft_auth: ['finance:user'] - post: - summary: create new financial transaction (requires enabled self service) - tags: - - 1. User - - 6. FinancialTransaction - parameters: - - in: body - name: body - description: financial transaction to create - required: true - schema: - $ref: '#/definitions/FinancialTransactionForCreate' - responses: - 200: - description: success - schema: - type: object - properties: - financial_transaction: - $ref: '#/definitions/FinancialTransaction' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: user has no ordergroup, is below minimum balance, self service is disabled, or missing scope - schema: - $ref: '#/definitions/Error403' - 404: - description: financial transaction type not found - schema: - $ref: '#/definitions/Error404' - 422: - description: invalid parameter value - schema: - $ref: '#/definitions/Error422' - /user/financial_transactions/{id}: - parameters: - - $ref: '#/parameters/idInUrl' - get: - summary: find financial transaction by id - tags: - - 1. User - - 6. FinancialTransaction - responses: - 200: - description: success - schema: - type: object - properties: - financial_transaction: - $ref: '#/definitions/FinancialTransaction' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: user has no ordergroup or missing scope - schema: - $ref: '#/definitions/Error403' - 404: - description: not found - schema: - $ref: '#/definitions/Error404' - security: - - foodsoft_auth: ['finance:user'] - - /user/group_order_articles: - get: - summary: group order articles - tags: - - 1. User - - 2. Order - parameters: - - $ref: '#/parameters/page' - - $ref: '#/parameters/per_page' - - $ref: '#/parameters/q_ordered' - responses: - 200: - description: success - schema: - type: object - properties: - group_order_articles: - type: array - items: - $ref: '#/definitions/GroupOrderArticle' - meta: - $ref: '#/definitions/Meta' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: user has no ordergroup or missing scope - schema: - $ref: '#/definitions/Error403' - security: - - foodsoft_auth: ['group_orders:user'] - post: - summary: create new group order article - tags: - - 1. User - - 2. Order - parameters: - - in: body - name: body - description: group order article to create - required: true - schema: - $ref: '#/definitions/GroupOrderArticleForCreate' - responses: - 200: - description: success - schema: - type: object - properties: - group_order_article: - $ref: '#/definitions/GroupOrderArticle' - order_article: - $ref: '#/definitions/OrderArticle' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope - schema: - $ref: '#/definitions/Error403' - 404: - description: order article not found in open orders - schema: - $ref: '#/definitions/Error404' - 422: - description: invalid parameter value or group order article already exists - schema: - $ref: '#/definitions/Error422' - /user/group_order_articles/{id}: - parameters: - - $ref: '#/parameters/idInUrl' - get: - summary: find group order article by id - tags: - - 1. User - - 2. Order - responses: - 200: - description: success - schema: - type: object - properties: - group_order_article: - $ref: '#/definitions/GroupOrderArticle' - order_article: - $ref: '#/definitions/OrderArticle' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: user has no ordergroup or missing scope - schema: - $ref: '#/definitions/Error403' - 404: - description: not found - schema: - $ref: '#/definitions/Error404' - security: - - foodsoft_auth: ['group_orders:user'] - patch: - summary: update a group order article (but delete if quantity and tolerance are zero) - tags: - - 1. User - - 2. Order - parameters: - - $ref: '#/parameters/idInUrl' - - in: body - name: body - description: group order article update - required: true - schema: - $ref: '#/definitions/GroupOrderArticleForUpdate' - responses: - 200: - description: success - schema: - type: object - properties: - group_order_article: - $ref: '#/definitions/GroupOrderArticle' - order_article: - $ref: '#/definitions/OrderArticle' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope - schema: - $ref: '#/definitions/Error403' - 404: - description: order article not found in open orders - schema: - $ref: '#/definitions/Error404' - 422: - description: invalid parameter value - schema: - $ref: '#/definitions/Error422' - delete: - summary: remove group order article - tags: - - 1. User - - 2. Order - parameters: - - $ref: '#/parameters/idInUrl' - responses: - 200: - description: success - schema: - type: object - properties: - group_order_article: - $ref: '#/definitions/GroupOrderArticle' - order_article: - $ref: '#/definitions/OrderArticle' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope - schema: - $ref: '#/definitions/Error403' - 404: - description: order article not found in open orders - schema: - $ref: '#/definitions/Error404' - - /financial_transactions: - get: - summary: financial transactions - tags: - - 6. FinancialTransaction - parameters: - - $ref: '#/parameters/page' - - $ref: '#/parameters/per_page' - responses: - 200: - description: success - schema: - type: object - properties: - financial_transactions: - type: array - items: - $ref: '#/definitions/FinancialTransaction' - meta: - $ref: '#/definitions/Meta' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: missing scope or no permission - schema: - $ref: '#/definitions/Error403' - security: - - foodsoft_auth: ['finance:read', 'finance:write'] - /financial_transactions/{id}: - parameters: - - $ref: '#/parameters/idInUrl' - get: - summary: find financial transaction by id - tags: - - 6. FinancialTransaction - responses: - 200: - description: success - schema: - type: object - properties: - financial_transaction: - $ref: '#/definitions/FinancialTransaction' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: missing scope or no permission - schema: - $ref: '#/definitions/Error403' - 404: - description: not found - schema: - $ref: '#/definitions/Error404' - security: - - foodsoft_auth: ['finance:read', 'finance:write'] - /orders: - get: - summary: orders - tags: - - 2. Order - parameters: - - $ref: '#/parameters/page' - - $ref: '#/parameters/per_page' - responses: - 200: - description: success - schema: - type: object - properties: - orders: - type: array - items: - $ref: '#/definitions/Order' - meta: - $ref: '#/definitions/Meta' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: missing scope or no permission - schema: - $ref: '#/definitions/Error403' - security: - - foodsoft_auth: ['orders:read', 'orders:write'] - /orders/{id}: - parameters: - - $ref: '#/parameters/idInUrl' - get: - summary: find order by id - tags: - - 2. Order - responses: - 200: - description: success - schema: - type: object - properties: - order: - $ref: '#/definitions/Order' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: missing scope or no permission - schema: - $ref: '#/definitions/Error403' - 404: - description: not found - schema: - $ref: '#/definitions/Error404' - security: - - foodsoft_auth: ['orders:read', 'orders:write'] - /order_articles: - get: - summary: order articles - tags: - - 2. Order - parameters: - - $ref: '#/parameters/page' - - $ref: '#/parameters/per_page' - - $ref: '#/parameters/q_ordered' - responses: - 200: - description: success - schema: - type: object - properties: - order_articles: - type: array - items: - $ref: '#/definitions/OrderArticle' - meta: - $ref: '#/definitions/Meta' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: missing scope or no permission - schema: - $ref: '#/definitions/Error403' - security: - - foodsoft_auth: ['group_orders:user'] - /order_articles/{id}: - parameters: - - $ref: '#/parameters/idInUrl' - get: - summary: find order article by id - tags: - - 2. Order - responses: - 200: - description: success - schema: - type: object - properties: - order_article: - $ref: '#/definitions/OrderArticle' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: missing scope or no permission - schema: - $ref: '#/definitions/Error403' - 404: - description: not found - schema: - $ref: '#/definitions/Error404' - security: - - foodsoft_auth: ['orders:read', 'orders:write'] - /article_categories: - get: - summary: article categories - tags: - - 2. Category - parameters: - - $ref: '#/parameters/page' - - $ref: '#/parameters/per_page' - responses: - 200: - description: success - schema: - type: object - properties: - article_categories: - type: array - items: - $ref: '#/definitions/ArticleCategory' - meta: - $ref: '#/definitions/Meta' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - - security: - - foodsoft_auth: ['all'] - /article_categories/{id}: - parameters: - - $ref: '#/parameters/idInUrl' - get: - summary: find article category by id - tags: - - 2. Category - responses: - 200: - description: success - schema: - type: object - properties: - article_category: - $ref: '#/definitions/ArticleCategory' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 404: - description: not found - schema: - $ref: '#/definitions/Error404' - security: - - foodsoft_auth: ['all'] - - /financial_transaction_classes: - get: - summary: financial transaction classes - tags: - - 2. Category - parameters: - - $ref: '#/parameters/page' - - $ref: '#/parameters/per_page' - responses: - 200: - description: success - schema: - type: object - properties: - financial_transaction_classes: - type: array - items: - $ref: '#/definitions/FinancialTransactionClass' - meta: - $ref: '#/definitions/Meta' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - - security: - - foodsoft_auth: ['all'] - /financial_transaction_classes/{id}: - parameters: - - $ref: '#/parameters/idInUrl' - get: - summary: find financial transaction class by id - tags: - - 2. Category - responses: - 200: - description: success - schema: - type: object - properties: - financial_transaction_class: - $ref: '#/definitions/FinancialTransactionClass' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 404: - description: not found - schema: - $ref: '#/definitions/Error404' - security: - - foodsoft_auth: ['all'] - - /financial_transaction_types: - get: - summary: financial transaction types - tags: - - 2. Category - parameters: - - $ref: '#/parameters/page' - - $ref: '#/parameters/per_page' - responses: - 200: - description: success - schema: - type: object - properties: - financial_transaction_types: - type: array - items: - $ref: '#/definitions/FinancialTransactionType' - meta: - $ref: '#/definitions/Meta' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - - security: - - foodsoft_auth: ['all'] - /financial_transaction_types/{id}: - parameters: - - $ref: '#/parameters/idInUrl' - get: - summary: find financial transaction type by id - tags: - - 2. Category - responses: - 200: - description: success - schema: - type: object - properties: - financial_transaction_type: - $ref: '#/definitions/FinancialTransactionType' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 404: - description: not found - schema: - $ref: '#/definitions/Error404' - security: - - foodsoft_auth: ['all'] - - /config: - get: - summary: configuration variables - tags: - - 7. General - responses: - 200: - description: success - schema: - type: object - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - 403: - description: missing scope or no permission - schema: - $ref: '#/definitions/Error403' - security: - - foodsoft_auth: ['config:user', 'config:read', 'config:write'] - /navigation: - get: - summary: navigation - tags: - - 7. General - responses: - 200: - description: success - schema: - type: object - properties: - navigation: - $ref: '#/definitions/Navigation' - 401: - description: not logged-in - schema: - $ref: '#/definitions/Error401' - security: - - foodsoft_auth: [] - -parameters: - # url parameters - idInUrl: - name: id - type: integer - in: path - minimum: 1 - required: true - - # query parameters - page: - name: page - type: integer - in: query - description: page number - minimum: 0 - default: 0 - per_page: - name: per_page - type: integer - in: query - description: items per page - minimum: 0 - default: 20 - - # non-ransack query parameters - q_ordered: - name: q[ordered] - type: string - in: query - description: "'member' show articles ordered by the user's ordergroup, 'all' by all members, and 'supplier' ordered at the supplier" - enum: ['member', 'all', 'supplier'] - -definitions: - # models - User: - type: object - properties: - id: - type: integer - name: - type: string - description: full name - email: - type: string - description: email address - locale: - type: string - description: language code - required: ['id', 'name', 'email'] - - FinancialTransactionForCreate: - type: object - properties: - amount: - type: number - description: amount credited (negative for a debit transaction) - financial_transaction_type_id: - type: integer - description: id of the type of the transaction - note: - type: string - description: note entered with the transaction - required: ['amount', 'financial_transaction_type_id', 'note'] - FinancialTransaction: - allOf: - - $ref: '#/definitions/FinancialTransactionForCreate' - - type: object - properties: - id: - type: integer - user_id: - type: ['integer', 'null'] - description: id of user who entered the transaction (may be null for deleted users or 0 for a system user) - user_name: - type: ['string', 'null'] - description: name of user who entered the transaction (may be null or empty string for deleted users or system users) - financial_transaction_type_name: - type: string - description: name of the type of the transaction - created_at: - type: string - format: date-time - description: when the transaction was entered - required: ['id', 'user_id', 'user_name', 'financial_transaction_type_name', 'created_at'] - - FinancialTransactionClass: - type: object - properties: - id: - type: integer - name: - type: string - description: full name - required: ['id', 'name'] - - FinancialTransactionType: - type: object - properties: - id: - type: integer - name: - type: string - description: full name - name_short: - type: ['string', 'null'] - description: short name (used for bank transfers) - bank_account_id: - type: ['integer', 'null'] - description: id of the bank account used for this transaction type - bank_account_name: - type: ['string', 'null'] - description: name of the bank account used for this transaction type - bank_account_iban: - type: ['string', 'null'] - description: IBAN of the bank account used for this transaction type - financial_transaction_class_id: - type: integer - description: id of the class of the transaction - financial_transaction_class_name: - type: string - description: name of the class of the transaction - required: ['id', 'name', 'financial_transaction_class_id', 'financial_transaction_class_name'] - - FinanceOverview: - type: object - properties: - account_balance: - type: number - description: booked accout balance of ordergroup - available_funds: - type: number - description: fund available to order articles - financial_transaction_class_sums: - type: array - items: - type: object - properties: - id: - type: integer - description: id of the financial transaction class - name: - type: string - description: name of the financial transaction class - amount: - type: number - description: sum of the amounts belonging to the financial transaction class - required: ['id', 'name', 'amount'] - required: ['account_balance', 'available_funds', 'financial_transaction_class_sums'] - - ArticleCategory: - type: object - properties: - id: - type: integer - name: - type: string - required: ['id', 'name'] - - Order: - type: object - properties: - id: - type: integer - name: - type: string - description: name of the order's supplier (or stock) - starts: - type: string - format: date-time - description: when the order was opened - ends: - type: ['string', 'null'] - format: date-time - description: when the order will close or was closed - boxfill: - type: ['string', 'null'] - format: date-time - description: when the order will enter or entered the boxfill phase - pickup: - type: ['string', 'null'] - format: date - description: pickup date - is_open: - type: boolean - description: if the order is currently open or not - is_boxfill: - type: boolean - description: if the order is currently in the boxfill phase or not - - Article: - type: object - properties: - id: - type: integer - name: - type: string - supplier_id: - type: integer - description: id of supplier, or 0 for stock articles - supplier_name: - type: ['string', 'null'] - description: name of the supplier, or null for stock articles - unit: - type: string - description: amount of each unit, e.g. "100 g" or "kg" - unit_quantity: - type: integer - description: units can only be ordered from the supplier in multiples of unit_quantity - note: - type: ['string', 'null'] - description: generic note - manufacturer: - type: ['string', 'null'] - description: manufacturer - origin: - type: ['string', 'null'] - description: origin, preferably (starting with a) 2-letter ISO country code - article_category_id: - type: integer - description: id of article category - quantity_available: - type: integer - description: number of units available (only present on stock articles) - required: ['id', 'name', 'supplier_id', 'supplier_name', 'unit', 'unit_quantity', 'note', 'manufacturer', 'origin', 'article_category_id'] - - OrderArticle: - type: object - properties: - id: - type: integer - order_id: - type: integer - description: id of order this order article belongs to - price: - type: number - format: float - description: foodcoop price - quantity: - type: integer - description: number of units ordered by members - tolerance: - type: integer - description: number of extra units that members are willing to buy to fill a box - units_to_order: - type: integer - description: number of units to order from the supplier - article: - $ref: '#/definitions/Article' - - GroupOrderArticleForUpdate: - type: object - properties: - quantity: - type: integer - description: number of units ordered by the user's ordergroup - tolerance: - type: integer - description: number of extra units the user's ordergroup is willing to buy for filling a box - GroupOrderArticleForCreate: - allOf: - - $ref: '#/definitions/GroupOrderArticleForUpdate' - - type: object - properties: - order_article_id: - type: integer - description: id of order article - GroupOrderArticle: - allOf: - - $ref: '#/definitions/GroupOrderArticleForCreate' - - type: object - properties: - id: - type: integer - result: - type: number - format: float - description: number of units the user's ordergroup will receive or has received - total_price: - type: number - format: float - description: total price of this group order article - - Navigation: - type: array - items: - type: object - properties: - name: - type: string - description: title - url: - type: string - description: link - items: - $ref: '#/definitions/Navigation' - required: ['name'] - minProperties: 2 # name+url or name+items - - # collection meta object in root of a response - Meta: - type: object - properties: - page: - type: integer - description: page number of the returned collection - per_page: - type: integer - description: number of items per page - total_pages: - type: integer - description: total number of pages - total_count: - type: integer - description: total number of items in the collection - required: ['page', 'per_page', 'total_pages', 'total_count'] - - Error: - type: object - properties: - error: - type: string - description: error code - error_description: - type: string - description: human-readable error message (localized) - Error404: - type: object - properties: - error: - type: string - description: 'not_found' - error_description: - $ref: '#/definitions/Error/properties/error_description' - Error401: - type: object - properties: - error: - type: string - description: 'unauthorized' - error_description: - $ref: '#/definitions/Error/properties/error_description' - Error403: - type: object - properties: - error: - type: string - description: 'forbidden or invalid_scope' - error_description: - $ref: '#/definitions/Error/properties/error_description' - Error422: - type: object - properties: - error: - type: string - description: unprocessable entity - error_description: - $ref: '#/definitions/Error/properties/error_description' - - -securityDefinitions: - foodsoft_auth: - type: oauth2 - flow: implicit - authorizationUrl: http://localhost:3000/f/oauth/authorize - scopes: - config:user: reading Foodsoft configuration for regular users - config:read: reading Foodsoft configuration values - config:write: reading and updating Foodsoft configuration values - finance:user: accessing your own financial transactions - finance:read: reading all financial transactions - finance:write: reading and creating financial transactions - user:read: reading your own user profile - user:write: reading and updating your own user profile - offline_access: retain access after user has logged out diff --git a/spec/api/v1/order_articles_spec.rb b/spec/api/v1/order_articles_spec.rb deleted file mode 100644 index e65867db..00000000 --- a/spec/api/v1/order_articles_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'spec_helper' - -# Most routes are tested in the swagger_spec, this tests (non-ransack) parameters. -describe Api::V1::OrderArticlesController, type: :controller do - include ApiOAuth - let(:api_scopes) { ['orders:read'] } - - let(:json_order_articles) { json_response['order_articles'] } - let(:json_order_article_ids) { json_order_articles.map { |joa| joa["id"] } } - - describe "GET :index" do - context "with param q[ordered]" do - let(:order) { create(:order, article_count: 4) } - let(:order_articles) { order.order_articles } - - before do - order_articles[0].update!(quantity: 0, tolerance: 0, units_to_order: 0) - order_articles[1].update!(quantity: 1, tolerance: 0, units_to_order: 0) - order_articles[2].update!(quantity: 0, tolerance: 1, units_to_order: 0) - order_articles[3].update!(quantity: 0, tolerance: 0, units_to_order: 1) - end - - it "(unset)" do - get :index, params: { foodcoop: 'f' } - expect(json_order_articles.count).to eq 4 - end - - it "all" do - get :index, params: { foodcoop: 'f', q: { ordered: 'all' } } - expect(json_order_article_ids).to match_array order_articles[1..2].map(&:id) - end - - it "supplier" do - get :index, params: { foodcoop: 'f', q: { ordered: 'supplier' } } - expect(json_order_article_ids).to match_array [order_articles[3].id] - end - - it "member" do - get :index, params: { foodcoop: 'f', q: { ordered: 'member' } } - expect(json_order_articles.count).to eq 0 - end - - context "when ordered by user" do - let(:user) { create(:user, :ordergroup) } - let(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) } - - before do - create(:group_order_article, group_order: go, order_article: order_articles[1], quantity: 1) - create(:group_order_article, group_order: go, order_article: order_articles[2], tolerance: 0) - end - - it "member" do - get :index, params: { foodcoop: 'f', q: { ordered: 'member' } } - expect(json_order_article_ids).to match_array order_articles[1..2].map(&:id) - end - end - end - end -end diff --git a/spec/api/v1/swagger_spec.rb b/spec/api/v1/swagger_spec.rb deleted file mode 100644 index 5202af83..00000000 --- a/spec/api/v1/swagger_spec.rb +++ /dev/null @@ -1,284 +0,0 @@ -require 'spec_helper' -require 'apivore' - -# we want to load a local file in YAML-format instead of a served JSON file -class SwaggerCheckerFile < Apivore::SwaggerChecker - def fetch_swagger! - YAML.load(File.read(swagger_path)) - end -end - -describe 'API v1', :skip, type: :apivore, order: :defined do - include ApiHelper - - subject { SwaggerCheckerFile.instance_for Rails.root.join('doc', 'swagger.v1.yml') } - - context 'has valid paths' do - # context 'user' do - # let(:api_scopes) { ['user:read'] } - # # create multiple users to make sure we're getting the authenticated user, not just any - # let!(:other_user_1) { create :user } - # let!(:user) { create :user } - # let!(:other_user_2) { create :user } - - # it { is_expected.to validate(:get, '/user', 200, api_auth) } - # it { is_expected.to validate(:get, '/user', 401) } - - # # it_handles_invalid_token_and_scope(:get, '/user') - # end - - context 'user/financial_overview' do - let(:api_scopes) { ['finance:user'] } - let!(:user) { create :user, :ordergroup } - - it { is_expected.to validate(:get, '/user/financial_overview', 200, api_auth) } - it { is_expected.to validate(:get, '/user/financial_overview', 401) } - - # it_handles_invalid_token_and_scope(:get, '/user/financial_overview') - end - - context 'user/financial_transactions' do - let(:api_scopes) { ['finance:user'] } - let(:other_user) { create :user, :ordergroup } - let!(:other_ft_1) { create :financial_transaction, ordergroup: other_user.ordergroup } - - context 'without ordergroup' do - it { is_expected.to validate(:get, '/user/financial_transactions', 403, api_auth) } - it { is_expected.to validate(:get, '/user/financial_transactions/{id}', 403, api_auth({ 'id' => other_ft_1.id })) } - end - - context 'with ordergroup' do - let(:user) { create :user, :ordergroup } - let!(:ft_1) { create :financial_transaction, ordergroup: user.ordergroup } - let!(:ft_2) { create :financial_transaction, ordergroup: user.ordergroup } - let!(:ft_3) { create :financial_transaction, ordergroup: user.ordergroup } - - let(:create_params) { { '_data' => { financial_transaction: { amount: 1, financial_transaction_type_id: ft_1.financial_transaction_type.id, note: 'note' } } } } - - it { is_expected.to validate(:get, '/user/financial_transactions', 200, api_auth) } - it { is_expected.to validate(:get, '/user/financial_transactions/{id}', 200, api_auth({ 'id' => ft_2.id })) } - it { is_expected.to validate(:get, '/user/financial_transactions/{id}', 404, api_auth({ 'id' => other_ft_1.id })) } - it { is_expected.to validate(:get, '/user/financial_transactions/{id}', 404, api_auth({ 'id' => FinancialTransaction.last.id + 1 })) } - - context 'without using self service' do - it { is_expected.to validate(:post, '/user/financial_transactions', 403, api_auth(create_params)) } - end - - context 'with using self service' do - before { FoodsoftConfig[:use_self_service] = true } - - it { is_expected.to validate(:post, '/user/financial_transactions', 200, api_auth(create_params)) } - - context 'with invalid financial transaction type' do - let(:create_params) { { '_data' => { financial_transaction: { amount: 1, financial_transaction_type_id: -1, note: 'note' } } } } - - it { is_expected.to validate(:post, '/user/financial_transactions', 404, api_auth(create_params)) } - end - - context 'without note' do - let(:create_params) { { '_data' => { financial_transaction: { amount: 1, financial_transaction_type_id: ft_1.financial_transaction_type.id } } } } - - it { is_expected.to validate(:post, '/user/financial_transactions', 422, api_auth(create_params)) } - end - - context 'without enough balance' do - before { FoodsoftConfig[:minimum_balance] = 1000 } - - it { is_expected.to validate(:post, '/user/financial_transactions', 403, api_auth(create_params)) } - end - end - - # it_handles_invalid_token_and_scope(:get, '/user/financial_transactions') - # it_handles_invalid_token_and_scope(:post, '/user/financial_transactions', -> { api_auth(create_params) }) - # it_handles_invalid_token_and_scope(:get, '/user/financial_transactions/{id}', -> { api_auth('id' => ft_2.id) }) - end - end - - context 'user/group_order_articles' do - let(:api_scopes) { ['group_orders:user'] } - let(:order) { create(:order, article_count: 2) } - - let(:user_2) { create :user, :ordergroup } - let(:group_order_2) { create(:group_order, order: order, ordergroup: user_2.ordergroup) } - let!(:goa_2) { create :group_order_article, order_article: order.order_articles[0], group_order: group_order_2 } - - before { group_order_2.update_price!; user_2.ordergroup.update_stats! } - - context 'without ordergroup' do - it { is_expected.to validate(:get, '/user/group_order_articles', 403, api_auth) } - it { is_expected.to validate(:get, '/user/group_order_articles/{id}', 403, api_auth({ 'id' => goa_2.id })) } - end - - context 'with ordergroup' do - let(:user) { create :user, :ordergroup } - let(:update_params) { { 'id' => goa.id, '_data' => { group_order_article: { quantity: goa.quantity + 1, tolerance: 0 } } } } - let(:create_params) { { '_data' => { group_order_article: { order_article_id: order.order_articles[1].id, quantity: 1 } } } } - let(:group_order) { create(:group_order, order: order, ordergroup: user.ordergroup) } - let!(:goa) { create :group_order_article, order_article: order.order_articles[0], group_order: group_order } - - before { group_order.update_price!; user.ordergroup.update_stats! } - - it { is_expected.to validate(:get, '/user/group_order_articles', 200, api_auth) } - it { is_expected.to validate(:get, '/user/group_order_articles/{id}', 200, api_auth({ 'id' => goa.id })) } - it { is_expected.to validate(:get, '/user/group_order_articles/{id}', 404, api_auth({ 'id' => goa_2.id })) } - it { is_expected.to validate(:get, '/user/group_order_articles/{id}', 404, api_auth({ 'id' => GroupOrderArticle.last.id + 1 })) } - - it { is_expected.to validate(:post, '/user/group_order_articles', 200, api_auth(create_params)) } - it { is_expected.to validate(:patch, '/user/group_order_articles/{id}', 200, api_auth(update_params)) } - it { is_expected.to validate(:delete, '/user/group_order_articles/{id}', 200, api_auth({ 'id' => goa.id })) } - - context 'with an existing group_order_article' do - let(:create_params) { { '_data' => { group_order_article: { order_article_id: order.order_articles[0].id, quantity: 1 } } } } - - it { is_expected.to validate(:post, '/user/group_order_articles', 422, api_auth(create_params)) } - end - - context 'with invalid parameter values' do - let(:create_params) { { '_data' => { group_order_article: { order_article_id: order.order_articles[0].id, quantity: -1 } } } } - let(:update_params) { { 'id' => goa.id, '_data' => { group_order_article: { quantity: -1, tolerance: 0 } } } } - - it { is_expected.to validate(:post, '/user/group_order_articles', 422, api_auth(create_params)) } - it { is_expected.to validate(:patch, '/user/group_order_articles/{id}', 422, api_auth(update_params)) } - end - - context 'with a closed order' do - let(:order) { create(:order, article_count: 2, state: :finished) } - - it { is_expected.to validate(:post, '/user/group_order_articles', 404, api_auth(create_params)) } - it { is_expected.to validate(:patch, '/user/group_order_articles/{id}', 404, api_auth(update_params)) } - it { is_expected.to validate(:delete, '/user/group_order_articles/{id}', 404, api_auth({ 'id' => goa.id })) } - end - - context 'without enough balance' do - before { FoodsoftConfig[:minimum_balance] = 1000 } - - it { is_expected.to validate(:post, '/user/group_order_articles', 403, api_auth(create_params)) } - it { is_expected.to validate(:patch, '/user/group_order_articles/{id}', 403, api_auth(update_params)) } - it { is_expected.to validate(:delete, '/user/group_order_articles/{id}', 200, api_auth({ 'id' => goa.id })) } - end - - context 'without enough apple points' do - before { allow_any_instance_of(Ordergroup).to receive(:not_enough_apples?).and_return(true) } - - it { is_expected.to validate(:post, '/user/group_order_articles', 403, api_auth(create_params)) } - it { is_expected.to validate(:patch, '/user/group_order_articles/{id}', 403, api_auth(update_params)) } - it { is_expected.to validate(:delete, '/user/group_order_articles/{id}', 200, api_auth({ 'id' => goa.id })) } - end - - # it_handles_invalid_token_and_scope(:get, '/user/group_order_articles') - # it_handles_invalid_token_and_scope(:post, '/user/group_order_articles', -> { api_auth(create_params) }) - # it_handles_invalid_token_and_scope(:get, '/user/group_order_articles/{id}', -> { api_auth({ 'id' => goa.id }) }) - # it_handles_invalid_token_and_scope(:patch, '/user/group_order_articles/{id}', -> { api_auth(update_params) }) - # it_handles_invalid_token_and_scope(:delete, '/user/group_order_articles/{id}', -> { api_auth({ 'id' => goa.id }) }) - end - end - - context 'config' do - let(:api_scopes) { ['config:user'] } - - it { is_expected.to validate(:get, '/config', 200, api_auth) } - it { is_expected.to validate(:get, '/config', 401) } - - # it_handles_invalid_token_and_scope(:get, '/config') - end - - context 'navigation' do - it { is_expected.to validate(:get, '/navigation', 200, api_auth) } - it { is_expected.to validate(:get, '/navigation', 401) } - - # #it_handles_invalid_token(:get, '/navigation') - end - - context 'financial_transactions' do - let(:api_scopes) { ['finance:read'] } - let(:user) { create(:user, :role_finance) } - let(:other_user) { create :user, :ordergroup } - let!(:ft_1) { create :financial_transaction, ordergroup: other_user.ordergroup } - let!(:ft_2) { create :financial_transaction, ordergroup: other_user.ordergroup } - - it { is_expected.to validate(:get, '/financial_transactions', 200, api_auth) } - it { is_expected.to validate(:get, '/financial_transactions/{id}', 200, api_auth({ 'id' => ft_2.id })) } - it { is_expected.to validate(:get, '/financial_transactions/{id}', 404, api_auth({ 'id' => FinancialTransaction.last.id + 1 })) } - - context 'without role_finance' do - let(:user) { create(:user) } - - it { is_expected.to validate(:get, '/financial_transactions', 403, api_auth) } - it { is_expected.to validate(:get, '/financial_transactions/{id}', 403, api_auth({ 'id' => ft_2.id })) } - end - - # it_handles_invalid_token_and_scope(:get, '/financial_transactions') - # it_handles_invalid_token_and_scope(:get, '/financial_transactions/{id}', -> { api_auth({ 'id' => ft_2.id }) }) - end - - context 'financial_transaction_classes' do - let!(:cla_1) { create :financial_transaction_class } - let!(:cla_2) { create :financial_transaction_class } - - it { is_expected.to validate(:get, '/financial_transaction_classes', 200, api_auth) } - it { is_expected.to validate(:get, '/financial_transaction_classes/{id}', 200, api_auth({ 'id' => cla_2.id })) } - it { is_expected.to validate(:get, '/financial_transaction_classes/{id}', 404, api_auth({ 'id' => cla_2.id + 1 })) } - - #it_handles_invalid_token(:get, '/financial_transaction_classes') - #it_handles_invalid_token(:get, '/financial_transaction_classes/{id}', -> { api_auth({ 'id' => cla_1.id }) }) - end - - context 'financial_transaction_types' do - let!(:tpy_1) { create :financial_transaction_type } - let!(:tpy_2) { create :financial_transaction_type } - - it { is_expected.to validate(:get, '/financial_transaction_types', 200, api_auth) } - it { is_expected.to validate(:get, '/financial_transaction_types/{id}', 200, api_auth({ 'id' => tpy_2.id })) } - it { is_expected.to validate(:get, '/financial_transaction_types/{id}', 404, api_auth({ 'id' => tpy_2.id + 1 })) } - - ##it_handles_invalid_token(:get, '/financial_transaction_types') - ##it_handles_invalid_token(:get, '/financial_transaction_types/{id}', -> { api_auth({ 'id' => tpy_1.id }) }) - end - - context 'orders' do - let(:api_scopes) { ['orders:read'] } - let!(:order) { create :order } - - it { is_expected.to validate(:get, '/orders', 200, api_auth) } - it { is_expected.to validate(:get, '/orders/{id}', 200, api_auth({ 'id' => order.id })) } - it { is_expected.to validate(:get, '/orders/{id}', 404, api_auth({ 'id' => Order.last.id + 1 })) } - - # #it_handles_invalid_token_and_scope(:get, '/orders') - # #it_handles_invalid_token_and_scope(:get, '/orders/{id}', -> { api_auth({ 'id' => order.id }) }) - end - - context 'order_articles' do - let(:api_scopes) { ['orders:read'] } - let!(:order_article) { create(:order, article_count: 1).order_articles.first } - let!(:stock_article) { create(:stock_article) } - let!(:stock_order_article) { create(:stock_order, article_ids: [stock_article.id]).order_articles.first } - - it { is_expected.to validate(:get, '/order_articles', 200, api_auth) } - it { is_expected.to validate(:get, '/order_articles/{id}', 200, api_auth({ 'id' => order_article.id })) } - it { is_expected.to validate(:get, '/order_articles/{id}', 200, api_auth({ 'id' => stock_order_article.id })) } - it { is_expected.to validate(:get, '/order_articles/{id}', 404, api_auth({ 'id' => Article.last.id + 1 })) } - - # it_handles_invalid_token_and_scope(:get, '/order_articles') - # it_handles_invalid_token_and_scope(:get, '/order_articles/{id}', -> { api_auth({ 'id' => order_article.id }) }) - end - - context 'article_categories' do - let!(:cat_1) { create :article_category } - let!(:cat_2) { create :article_category } - - it { is_expected.to validate(:get, '/article_categories', 200, api_auth) } - it { is_expected.to validate(:get, '/article_categories/{id}', 200, api_auth({ 'id' => cat_2.id })) } - it { is_expected.to validate(:get, '/article_categories/{id}', 404, api_auth({ 'id' => cat_2.id + 1 })) } - - #it_handles_invalid_token(:get, '/article_categories') - #it_handles_invalid_token(:get, '/article_categories/{id}', -> { api_auth({ 'id' => cat_1.id }) }) - end - end - - # needs to be last context so it is always run at the end - context 'and finally' do - it 'tests all documented routes' do - is_expected.to validate_all_paths - end - end -end diff --git a/spec/api/v1/user/financial_transactions_spec.rb b/spec/api/v1/user/financial_transactions_spec.rb deleted file mode 100644 index c7e8f826..00000000 --- a/spec/api/v1/user/financial_transactions_spec.rb +++ /dev/null @@ -1,109 +0,0 @@ -require 'spec_helper' - -# Most routes are tested in the swagger_spec, this tests endpoints that change data. -describe Api::V1::User::FinancialTransactionsController, type: :controller do - include ApiOAuth - let(:user) { create(:user, :ordergroup) } - let(:api_scopes) { ['finance:user'] } - - let(:ftc1) { create :financial_transaction_class } - let(:ftc2) { create :financial_transaction_class } - let(:ftt1) { create :financial_transaction_type, financial_transaction_class: ftc1 } - let(:ftt2) { create :financial_transaction_type, financial_transaction_class: ftc2 } - let(:ftt3) { create :financial_transaction_type, financial_transaction_class: ftc2 } - - let(:amount) { rand(-100..100) } - let(:note) { Faker::Lorem.sentence } - - let(:json_ft) { json_response['financial_transaction'] } - - shared_examples "financial_transactions endpoint success" do - before { request } - - it "returns status 200" do - expect(response).to have_http_status :ok - end - end - - shared_examples "financial_transactions create/update success" do - include_examples "financial_transactions endpoint success" - - it "returns the financial_transaction" do - expect(json_ft['id']).to be_present - expect(json_ft['financial_transaction_type_id']).to eq ftt1.id - expect(json_ft['financial_transaction_type_name']).to eq ftt1.name - expect(json_ft['amount']).to eq amount - expect(json_ft['note']).to eq note - expect(json_ft['user_id']).to eq user.id - end - - it "updates the financial_transaction" do - resulting_ft = FinancialTransaction.where(id: json_ft['id']).first - expect(resulting_ft).to be_present - expect(resulting_ft.financial_transaction_type).to eq ftt1 - expect(resulting_ft.amount).to eq amount - expect(resulting_ft.note).to eq note - expect(resulting_ft.user).to eq user - end - end - - shared_examples "financial_transactions endpoint failure" do |status| - it "returns status #{status}" do - request - expect(response.status).to eq status - end - - it "does not change the ordergroup" do - expect { request }.to_not change { - user.ordergroup.attributes - } - end - - it "does not change the financial_transactions of ordergroup" do - expect { request }.to_not change { - user.ordergroup.financial_transactions.count - } - end - end - - describe "POST :create" do - let(:ft_params) { { amount: amount, financial_transaction_type_id: ftt1.id, note: note } } - let(:request) { post :create, params: { financial_transaction: ft_params, foodcoop: 'f' } } - - context 'without using self service' do - include_examples "financial_transactions endpoint failure", 403 - end - - context 'with using self service' do - before { FoodsoftConfig[:use_self_service] = true } - - context "with no existing financial transaction" do - include_examples "financial_transactions create/update success" - end - - context "with existing financial transaction" do - before { user.ordergroup.add_financial_transaction! 5000, 'for ordering', user, ftt3 } - - include_examples "financial_transactions create/update success" - end - - context "with invalid financial transaction type" do - let(:ft_params) { { amount: amount, financial_transaction_type_id: -1, note: note } } - - include_examples "financial_transactions endpoint failure", 404 - end - - context "without note" do - let(:ft_params) { { amount: amount, financial_transaction_type_id: ftt1.id } } - - include_examples "financial_transactions endpoint failure", 422 - end - - context 'without enough balance' do - before { FoodsoftConfig[:minimum_balance] = 1000 } - - include_examples "financial_transactions endpoint failure", 403 - end - end - end -end diff --git a/spec/api/v1/user/group_order_articles_spec.rb b/spec/api/v1/user/group_order_articles_spec.rb deleted file mode 100644 index 3bfa299e..00000000 --- a/spec/api/v1/user/group_order_articles_spec.rb +++ /dev/null @@ -1,220 +0,0 @@ -require 'spec_helper' - -# Most routes are tested in the swagger_spec, this tests endpoints that change data. -describe Api::V1::User::GroupOrderArticlesController, type: :controller do - include ApiOAuth - let(:user) { create(:user, :ordergroup) } - let(:json_goa) { json_response['group_order_article'] } - let(:json_oa) { json_response['order_article'] } - let(:api_scopes) { ['group_orders:user'] } - - let(:order) { create(:order, article_count: 1) } - let(:oa_1) { order.order_articles.first } - - let(:other_quantity) { rand(1..10) } - let(:other_tolerance) { rand(1..10) } - let(:user_other) { create(:user, :ordergroup) } - let!(:go_other) { create(:group_order, order: order, ordergroup: user_other.ordergroup) } - let!(:goa_other) { create(:group_order_article, group_order: go_other, order_article: oa_1, quantity: other_quantity, tolerance: other_tolerance) } - - before { go_other.update_price!; user_other.ordergroup.update_stats! } - - shared_examples "group_order_articles endpoint success" do - before { request } - - it "returns status 200" do - expect(response).to have_http_status :ok - end - - it "returns the order_article" do - expect(json_oa['id']).to eq oa_1.id - expect(json_oa['quantity']).to eq new_quantity + other_quantity - expect(json_oa['tolerance']).to eq new_tolerance + other_tolerance - end - - it "updates the group_order" do - go = nil - expect { - request - go = user.ordergroup.group_orders.where(order: order).last - }.to change { go&.updated_by }.to(user) - .and change { go&.price } - end - end - - shared_examples "group_order_articles create/update success" do - include_examples "group_order_articles endpoint success" - - it "returns the group_order_article" do - expect(json_goa['id']).to be_present - expect(json_goa['order_article_id']).to eq oa_1.id - expect(json_goa['quantity']).to eq new_quantity - expect(json_goa['tolerance']).to eq new_tolerance - end - - it "updates the group_order_article" do - resulting_goa = GroupOrderArticle.where(id: json_goa['id']).first - expect(resulting_goa).to be_present - expect(resulting_goa.quantity).to eq new_quantity - expect(resulting_goa.tolerance).to eq new_tolerance - end - end - - shared_examples "group_order_articles endpoint failure" do |status| - it "returns status #{status}" do - request - expect(response.status).to eq status - end - - it "does not change the group_order" do - expect { request }.to_not change { - go = user.ordergroup.group_orders.where(order: order).last - go&.attributes - } - end - - it "does not change the group_order_article" do - expect { request }.to_not change { - goa = GroupOrderArticle.joins(:group_order) - .where(order_article_id: oa_1.id, group_orders: { ordergroup: user.ordergroup }).last - goa&.attributes - } - end - end - - describe "POST :create" do - let(:new_quantity) { rand(1..10) } - let(:new_tolerance) { rand(1..10) } - - let(:goa_params) { { order_article_id: oa_1.id, quantity: new_quantity, tolerance: new_tolerance } } - let(:request) { post :create, params: { group_order_article: goa_params, foodcoop: 'f' } } - - context "with no existing group_order" do - include_examples "group_order_articles create/update success" - end - - context "with an existing group_order" do - let!(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) } - - include_examples "group_order_articles create/update success" - end - - context "with an existing group_order_article" do - let!(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) } - let!(:goa) { create(:group_order_article, group_order: go, order_article: oa_1, quantity: 0, tolerance: 1) } - - before { go.update_price!; user.ordergroup.update_stats! } - - include_examples "group_order_articles endpoint failure", 422 - end - - context "with invalid parameter values" do - let(:goa_params) { { order_article_id: oa_1.id, quantity: -1, tolerance: new_tolerance } } - - include_examples "group_order_articles endpoint failure", 422 - end - - context 'with a closed order' do - let(:order) { create(:order, article_count: 1, state: :finished) } - - include_examples "group_order_articles endpoint failure", 404 - end - - context 'without enough balance' do - before { FoodsoftConfig[:minimum_balance] = 1000 } - - include_examples "group_order_articles endpoint failure", 403 - end - - context 'without enough apple points' do - before { allow_any_instance_of(Ordergroup).to receive(:not_enough_apples?).and_return(true) } - - include_examples "group_order_articles endpoint failure", 403 - end - end - - describe "PATCH :update" do - let(:new_quantity) { rand(2..10) } - let(:goa_params) { { quantity: new_quantity, tolerance: new_tolerance } } - let(:request) { patch :update, params: { id: goa.id, group_order_article: goa_params, foodcoop: 'f' } } - let(:new_tolerance) { rand(2..10) } - - let!(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) } - let!(:goa) { create(:group_order_article, group_order: go, order_article: oa_1, quantity: 1, tolerance: 0) } - - before { go.update_price!; user.ordergroup.update_stats! } - - context "happy flow" do - include_examples "group_order_articles create/update success" - end - - context "with invalid parameter values" do - let(:goa_params) { { order_article_id: oa_1.id, quantity: -1, tolerance: new_tolerance } } - - include_examples "group_order_articles endpoint failure", 422 - end - - context 'with a closed order' do - let(:order) { create(:order, article_count: 1, state: :finished) } - - include_examples "group_order_articles endpoint failure", 404 - end - - context 'without enough balance' do - before { FoodsoftConfig[:minimum_balance] = 1000 } - - include_examples "group_order_articles endpoint failure", 403 - end - - context 'without enough apple points' do - before { allow_any_instance_of(Ordergroup).to receive(:not_enough_apples?).and_return(true) } - - include_examples "group_order_articles endpoint failure", 403 - end - end - - describe "DELETE :destroy" do - let(:new_quantity) { 0 } - let(:request) { delete :destroy, params: { id: goa.id, foodcoop: 'f' } } - let(:new_tolerance) { 0 } - - let!(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) } - let!(:goa) { create(:group_order_article, group_order: go, order_article: oa_1) } - - before { go.update_price!; user.ordergroup.update_stats! } - - shared_examples "group_order_articles destroy success" do - include_examples "group_order_articles endpoint success" - - it "does not return the group_order_article" do - expect(json_goa).to be_nil - end - - it "deletes the group_order_article" do - expect(GroupOrderArticle.where(id: goa.id)).to be_empty - end - end - - context "happy flow" do - include_examples "group_order_articles destroy success" - end - - context 'with a closed order' do - let(:order) { create(:order, article_count: 1, state: :finished) } - - include_examples "group_order_articles endpoint failure", 404 - end - - context 'without enough balance' do - before { FoodsoftConfig[:minimum_balance] = 1000 } - - include_examples "group_order_articles destroy success" - end - - context 'without enough apple points' do - before { allow_any_instance_of(Ordergroup).to receive(:not_enough_apples?).and_return(true) } - - include_examples "group_order_articles destroy success" - end - end -end diff --git a/spec/api/v1/user/ordergroup_spec.rb b/spec/api/v1/user/ordergroup_spec.rb deleted file mode 100644 index 5eacb63e..00000000 --- a/spec/api/v1/user/ordergroup_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -require 'spec_helper' - -describe Api::V1::User::OrdergroupController, type: :controller do - include ApiOAuth - let(:user) { create :user, :ordergroup } - let(:api_scopes) { ['finance:user'] } - - let(:ftc1) { create :financial_transaction_class } - let(:ftc2) { create :financial_transaction_class } - let(:ftt1) { create :financial_transaction_type, financial_transaction_class: ftc1 } - let(:ftt2) { create :financial_transaction_type, financial_transaction_class: ftc2 } - let(:ftt3) { create :financial_transaction_type, financial_transaction_class: ftc2 } - - describe "GET :financial_overview" do - let(:order) { create(:order, article_count: 1) } - let(:json_financial_overview) { json_response['financial_overview'] } - let(:oa_1) { order.order_articles.first } - - let!(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) } - let!(:goa) { create(:group_order_article, group_order: go, order_article: oa_1, quantity: 1, tolerance: 0) } - - before { go.update_price!; user.ordergroup.update_stats! } - - before do - og = user.ordergroup - og.add_financial_transaction!(-1, '-1', user, ftt1) - og.add_financial_transaction!(2, '2', user, ftt1) - og.add_financial_transaction!(3, '3', user, ftt1) - - og.add_financial_transaction!(-10, '-10', user, ftt2) - og.add_financial_transaction!(20, '20', user, ftt2) - og.add_financial_transaction!(30, '30', user, ftt2) - - og.add_financial_transaction!(-100, '-100', user, ftt3) - og.add_financial_transaction!(200, '200', user, ftt3) - og.add_financial_transaction!(300, '300', user, ftt3) - end - - it "returns correct values" do - get :financial_overview, params: { foodcoop: 'f' } - expect(json_financial_overview['account_balance']).to eq 444 - expect(json_financial_overview['available_funds']).to eq 444 - go.price - - ftcs = Hash[json_financial_overview['financial_transaction_class_sums'].map { |x| [x['id'], x] }] - - ftcs1 = ftcs[ftc1.id] - expect(ftcs1['name']).to eq ftc1.name - expect(ftcs1['amount']).to eq 4 - - ftcs2 = ftcs[ftc2.id] - expect(ftcs2['name']).to eq ftc2.name - expect(ftcs2['amount']).to eq 440 - end - end -end -- 2.45.2 From b35f33a6b8a4f26bfeb9544587d651fc2f522544 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 21 Nov 2022 13:17:14 +0100 Subject: [PATCH 07/46] fix style validations --- config/initializers/rswag_api.rb | 3 +-- config/initializers/rswag_ui.rb | 1 - spec/support/api_helper.rb | 4 ++-- spec/support/factory_bot.rb | 2 +- spec/swagger_helper.rb | 8 ++++---- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/config/initializers/rswag_api.rb b/config/initializers/rswag_api.rb index 4d72f687..e4b798f6 100644 --- a/config/initializers/rswag_api.rb +++ b/config/initializers/rswag_api.rb @@ -1,5 +1,4 @@ Rswag::Api.configure do |c| - # Specify a root folder where Swagger JSON files are located # This is used by the Swagger middleware to serve requests for API descriptions # NOTE: If you're using rswag-specs to generate Swagger, you'll need to ensure @@ -10,5 +9,5 @@ Rswag::Api.configure do |c| # The function will have access to the rack env for the current request # For example, you could leverage this to dynamically assign the "host" property # - #c.swagger_filter = lambda { |swagger, env| swagger['host'] = env['HTTP_HOST'] } + # c.swagger_filter = lambda { |swagger, env| swagger['host'] = env['HTTP_HOST'] } end diff --git a/config/initializers/rswag_ui.rb b/config/initializers/rswag_ui.rb index 0a768c17..cc9f2ef8 100644 --- a/config/initializers/rswag_ui.rb +++ b/config/initializers/rswag_ui.rb @@ -1,5 +1,4 @@ Rswag::Ui.configure do |c| - # List the Swagger endpoints that you want to be documented through the # swagger-ui. The first parameter is the path (absolute or relative to the UI # host) to the corresponding endpoint and the second is a title that will be diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index c5357e7d..5c2246a3 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -7,7 +7,7 @@ module ApiHelper let(:api_access_token) { create(:oauth2_access_token, resource_owner_id: user.id, scopes: api_scopes&.join(' ')).token } let(:Authorization) { "Bearer #{api_access_token}" } - def self.it_handles_invalid_token() + def self.it_handles_invalid_token context 'with invalid access token' do let(:Authorization) { 'abc' } @@ -18,7 +18,7 @@ module ApiHelper end end - def self.it_handles_invalid_scope() + def self.it_handles_invalid_scope context 'with invalid scope' do let(:api_scopes) { ['none'] } diff --git a/spec/support/factory_bot.rb b/spec/support/factory_bot.rb index 2cb72940..655548ee 100644 --- a/spec/support/factory_bot.rb +++ b/spec/support/factory_bot.rb @@ -1,4 +1,4 @@ RSpec.configure do |config| # load FactoryBot shortcuts create(), etc. config.include FactoryBot::Syntax::Methods -end \ No newline at end of file +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index c45fd0af..dfd4b187 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -101,7 +101,7 @@ RSpec.configure do |config| 'finance:write': 'reading and creating financial transactions', 'user:read': 'reading your own user profile', 'user:write': 'reading and updating your own user profile', - offline_access: 'retain access after user has logged out', + offline_access: 'retain access after user has logged out' } } } @@ -120,9 +120,9 @@ RSpec.configure do |config| ], security: [ oauth2: [ - 'user:read', - ], - ], + 'user:read' + ] + ] } } -- 2.45.2 From a8698d3b49fcfb7a6b5a466e4d9d0e731fc6e5b2 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 21 Nov 2022 13:45:37 +0100 Subject: [PATCH 08/46] restore hashie gem --- Gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Gemfile b/Gemfile index 4ff617d8..61562099 100644 --- a/Gemfile +++ b/Gemfile @@ -55,6 +55,7 @@ gem 'gaffe' gem 'ruby-filemagic' gem 'mime-types' gem 'midi-smtp-server' +gem 'hashie', '~> 3.4.6', require: false # https://github.com/westfieldlabs/apivore/issues/114 gem 'rswag-api' gem 'rswag-ui' -- 2.45.2 From e8303a8b146ee882e0330d762c269a00c4f974ff Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 21 Nov 2022 15:23:46 +0100 Subject: [PATCH 09/46] add config_spec --- spec/requests/api/config_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 spec/requests/api/config_spec.rb diff --git a/spec/requests/api/config_spec.rb b/spec/requests/api/config_spec.rb new file mode 100644 index 00000000..4932bc29 --- /dev/null +++ b/spec/requests/api/config_spec.rb @@ -0,0 +1,19 @@ +require 'swagger_helper' + +describe 'Navigation API', type: :request do + include ApiHelper + + path '/config' do + get 'configuration variables' do + tags 'General' + produces 'application/json' + let(:api_scopes) { ['config:user'] } + + response '200', 'success' do + run_test! + end + + it_handles_invalid_token_and_scope + end + end +end -- 2.45.2 From 71ae7051bc7523ba927de023784b864484e86441 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 21 Nov 2022 15:54:47 +0100 Subject: [PATCH 10/46] add navigation_spec --- spec/requests/api/navigation_spec.rb | 25 +++++++++++++++++++++++++ spec/swagger_helper.rb | 23 ++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 spec/requests/api/navigation_spec.rb diff --git a/spec/requests/api/navigation_spec.rb b/spec/requests/api/navigation_spec.rb new file mode 100644 index 00000000..9064c7ef --- /dev/null +++ b/spec/requests/api/navigation_spec.rb @@ -0,0 +1,25 @@ +require 'swagger_helper' + +describe 'Navigation API', type: :request do + include ApiHelper + + path '/navigation' do + get 'navigation' do + tags 'General' + produces 'application/json' + let(:api_scopes) { ['config:user'] } + + response '200', 'success' do + schema type: :object, properties: { + navigation: { + '$ref' => '#/components/schemas/Navigation' + } + } + + run_test! + end + + it_handles_invalid_token + end + end +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index dfd4b187..2380133e 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -16,7 +16,7 @@ RSpec.configure do |config| # the root example_group in your specs, e.g. describe '...', swagger_doc: 'v2/swagger.json' config.swagger_docs = { 'v1/swagger.yaml' => { - openapi: '3.0.1', + openapi: '3.0.3', info: { title: 'API V1', version: 'v1' @@ -24,6 +24,27 @@ RSpec.configure do |config| paths: {}, components: { schemas: { + Navigation: { + type: :array, + items: { + type: :object, + properties: { + name: { + type: :string, + description: 'title' + }, + url: { + type: :string, + description: 'link' + }, + items: { + '$ref': "#/components/schemas/Navigation" + } + }, + required: ['name'], + minProperties: 2 # name+url or name+items + } + }, Error: { type: :object, properties: { -- 2.45.2 From 1020035cfe5a4228e7987f2b35c686f706e53707 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 21 Nov 2022 15:59:20 +0100 Subject: [PATCH 11/46] rename tests according to api controllers --- spec/requests/api/{config_spec.rb => configs_spec.rb} | 2 +- spec/requests/api/{navigation_spec.rb => navigations_spec.rb} | 2 +- spec/requests/api/{user_spec.rb => user/users_spec.rb} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename spec/requests/api/{config_spec.rb => configs_spec.rb} (87%) rename spec/requests/api/{navigation_spec.rb => navigations_spec.rb} (90%) rename spec/requests/api/{user_spec.rb => user/users_spec.rb} (98%) diff --git a/spec/requests/api/config_spec.rb b/spec/requests/api/configs_spec.rb similarity index 87% rename from spec/requests/api/config_spec.rb rename to spec/requests/api/configs_spec.rb index 4932bc29..6a389148 100644 --- a/spec/requests/api/config_spec.rb +++ b/spec/requests/api/configs_spec.rb @@ -1,6 +1,6 @@ require 'swagger_helper' -describe 'Navigation API', type: :request do +describe 'Config', type: :request do include ApiHelper path '/config' do diff --git a/spec/requests/api/navigation_spec.rb b/spec/requests/api/navigations_spec.rb similarity index 90% rename from spec/requests/api/navigation_spec.rb rename to spec/requests/api/navigations_spec.rb index 9064c7ef..f6bb2d1a 100644 --- a/spec/requests/api/navigation_spec.rb +++ b/spec/requests/api/navigations_spec.rb @@ -1,6 +1,6 @@ require 'swagger_helper' -describe 'Navigation API', type: :request do +describe 'Navigation', type: :request do include ApiHelper path '/navigation' do diff --git a/spec/requests/api/user_spec.rb b/spec/requests/api/user/users_spec.rb similarity index 98% rename from spec/requests/api/user_spec.rb rename to spec/requests/api/user/users_spec.rb index ed002ba1..2b6020e9 100644 --- a/spec/requests/api/user_spec.rb +++ b/spec/requests/api/user/users_spec.rb @@ -1,6 +1,6 @@ require 'swagger_helper' -describe 'User API', type: :request do +describe 'User', type: :request do include ApiHelper path '/user' do -- 2.45.2 From 3b7eae694a657b89eb6361079b304099312a2c1c Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 21 Nov 2022 17:06:51 +0100 Subject: [PATCH 12/46] wip: article_categories spec --- spec/requests/api/article_categories_spec.rb | 40 +++++++++++++++++ spec/requests/api/navigations_spec.rb | 1 - spec/swagger_helper.rb | 46 ++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 spec/requests/api/article_categories_spec.rb diff --git a/spec/requests/api/article_categories_spec.rb b/spec/requests/api/article_categories_spec.rb new file mode 100644 index 00000000..cc22134c --- /dev/null +++ b/spec/requests/api/article_categories_spec.rb @@ -0,0 +1,40 @@ +require 'swagger_helper' + +describe 'Article Categories', type: :request do + include ApiHelper + + path '/article_categories' do + get 'article categories' do + tags 'Category' + produces 'application/json' + parameter name: :page, in: :query, schema: { '$ref' => '#/components/schemas/page' } + parameter name: :per_page, in: :query, schema: { '$ref' => '#/components/schemas/per_page' } + + let(:api_scopes) { ['orders:read'] } + let!(:order_article) { create(:order, article_count: 1).order_articles.first } + let!(:stock_article) { create(:stock_article) } + let!(:stock_order_article) { create(:stock_order, article_ids: [stock_article.id]).order_articles.first } + + + response '200', 'success' do + schema type: :object, properties: { + article_categories: { + type: :array, + items: { + '$ref': '#/components/schemas/ArticleCategory' + } + }, + meta: { + '$ref': '#/components/schemas/Meta' + } + } + + let(:page) { 0 } + let(:per_page) { 20 } + run_test! + end + + it_handles_invalid_token_and_scope + end + end +end diff --git a/spec/requests/api/navigations_spec.rb b/spec/requests/api/navigations_spec.rb index f6bb2d1a..c2312437 100644 --- a/spec/requests/api/navigations_spec.rb +++ b/spec/requests/api/navigations_spec.rb @@ -7,7 +7,6 @@ describe 'Navigation', type: :request do get 'navigation' do tags 'General' produces 'application/json' - let(:api_scopes) { ['config:user'] } response '200', 'success' do schema type: :object, properties: { diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 2380133e..b5555136 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -24,6 +24,52 @@ RSpec.configure do |config| paths: {}, components: { schemas: { + page: { + type: :integer, + description: 'page number', + minimum: 0, + default: 0 + }, + per_page: { + type: :integer, + description: 'items per page', + minimum: 0, + default: 20 + }, + ArticleCategory: { + type: :object, + properties: { + id: { + type: :integer + }, + name: { + type: :string + } + }, + required: %w[id name] + }, + Meta: { + type: :object, + properties: { + page: { + type: :integer, + description: 'page number of the returned collection' + }, + per_page: { + type: :integer, + description: 'number of items per page' + }, + total_pages: { + type: :integer, + description: 'total number of pages' + }, + total_count: { + type: :integer, + description: 'total number of items in the collection' + }, + required: %w[page per_page total_pages total_count] + } + }, Navigation: { type: :array, items: { -- 2.45.2 From 102e0e7ed67e668ff1a72715bb981473de388348 Mon Sep 17 00:00:00 2001 From: viehlieb Date: Fri, 25 Nov 2022 13:55:21 +0100 Subject: [PATCH 13/46] wip swagger spec article_categories --- spec/requests/api/article_categories_spec.rb | 69 ++++++++++++++++---- spec/swagger_helper.rb | 20 +++--- 2 files changed, 66 insertions(+), 23 deletions(-) diff --git a/spec/requests/api/article_categories_spec.rb b/spec/requests/api/article_categories_spec.rb index cc22134c..c16a0a99 100644 --- a/spec/requests/api/article_categories_spec.rb +++ b/spec/requests/api/article_categories_spec.rb @@ -7,34 +7,79 @@ describe 'Article Categories', type: :request do get 'article categories' do tags 'Category' produces 'application/json' - parameter name: :page, in: :query, schema: { '$ref' => '#/components/schemas/page' } - parameter name: :per_page, in: :query, schema: { '$ref' => '#/components/schemas/per_page' } + parameter name: "page[number]", in: :query, type: :integer, required: false + parameter name: "page[size]", in: :query, type: :integer, required: false - let(:api_scopes) { ['orders:read'] } let!(:order_article) { create(:order, article_count: 1).order_articles.first } let!(:stock_article) { create(:stock_article) } let!(:stock_order_article) { create(:stock_order, article_ids: [stock_article.id]).order_articles.first } - response '200', 'success' do + schema type: :object, properties: { + meta: { + '$ref' => '#/components/schemas/pagination' + }, + article_categories: { + type: :array, + items: { + '$ref': '#/components/schemas/ArticleCategory' + } + } + } + + let(:page) { { number: 1, size: 20 } } + run_test! + end + + it_handles_invalid_token + end + end + + path '/article_categories/{id}' do + get 'Retrieves an article category' do + tags 'Category' + produces 'application/json' + parameter name: :id, in: :path, type: :string + + response '200', 'article category found' do schema type: :object, properties: { article_categories: { type: :array, items: { '$ref': '#/components/schemas/ArticleCategory' } - }, - meta: { - '$ref': '#/components/schemas/Meta' } } - - let(:page) { 0 } - let(:per_page) { 20 } + let(:id) { ArticleCategory.create(name: 'dairy').id } run_test! end - it_handles_invalid_token_and_scope + response '401', 'not logged in' do + schema type: :object, properties: { + article_categories: { + type: :array, + items: { + '$ref': '#/components/schemas/ArticleCategory' + } + } + } + let(:Authorization) { 'abc' } + let(:id) { ArticleCategory.create(name: 'dairy').id } + run_test! + end + + response '404', 'article category not found' do + schema type: :object, properties: { + article_categories: { + type: :array, + items: { + '$ref': '#/components/schemas/ArticleCategory' + } + } + } + let(:id) { 'invalid' } + run_test! + end end end -end +end \ No newline at end of file diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index b5555136..dcabf6c3 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -24,17 +24,15 @@ RSpec.configure do |config| paths: {}, components: { schemas: { - page: { - type: :integer, - description: 'page number', - minimum: 0, - default: 0 - }, - per_page: { - type: :integer, - description: 'items per page', - minimum: 0, - default: 20 + pagination: { + type: :object, + properties: { + recordCount: { type: :integer }, + pageCount: { type: :integer }, + currentPage: { type: :integer }, + pageSize: { type: :integer } + }, + required: %w(recordCount pageCount currentPage pageSize) }, ArticleCategory: { type: :object, -- 2.45.2 From c6dd8a18a306cffbc1ce1c64222f3ca1109a57da Mon Sep 17 00:00:00 2001 From: viehlieb Date: Fri, 25 Nov 2022 14:52:02 +0100 Subject: [PATCH 14/46] rswag financial_transaction_class --- .../api/financial_transaction_classes_spec.rb | 82 +++++++++++++++++++ spec/swagger_helper.rb | 12 +++ 2 files changed, 94 insertions(+) create mode 100644 spec/requests/api/financial_transaction_classes_spec.rb diff --git a/spec/requests/api/financial_transaction_classes_spec.rb b/spec/requests/api/financial_transaction_classes_spec.rb new file mode 100644 index 00000000..2b832ea7 --- /dev/null +++ b/spec/requests/api/financial_transaction_classes_spec.rb @@ -0,0 +1,82 @@ +require 'swagger_helper' + +describe 'Financial Transaction Classes', type: :request do + include ApiHelper + + path '/financial_transaction_classes' do + get 'financial transaction classes' do + tags 'Category' + produces 'application/json' + parameter name: "page[number]", in: :query, type: :integer, required: false + parameter name: "page[size]", in: :query, type: :integer, required: false + + let!(:financial_transaction_class) { create(:financial_transaction_class) } + response '200', 'success' do + schema type: :object, properties: { + meta: { + '$ref' => '#/components/schemas/pagination' + }, + financial_transaction_class: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransactionClass' + } + } + } + + let(:page) { { number: 1, size: 20 } } + run_test! + end + + it_handles_invalid_token + end + end + + path '/financial_transaction_classes/{id}' do + get 'Retrieves an financial transaction class' do + tags 'Category' + produces 'application/json' + parameter name: :id, in: :path, type: :string + + response '200', 'financial transaction class found' do + schema type: :object, properties: { + financial_transaction_classes: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransactionClass' + } + } + } + let(:id) { FinancialTransactionClass.create(name: 'TestTransaction').id } + run_test! + end + + response '401', 'not logged in' do + schema type: :object, properties: { + financial_transaction_classes: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransactionClass' + } + } + } + let(:Authorization) { 'abc' } + let(:id) { FinancialTransactionClass.create(name: 'dairy').id } + run_test! + end + + response '404', 'financial transaction class not found' do + schema type: :object, properties: { + financial_transaction_classes: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransactionClass' + } + } + } + let(:id) { 'invalid' } + run_test! + end + end + end +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index dcabf6c3..7fed0c91 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -46,6 +46,18 @@ RSpec.configure do |config| }, required: %w[id name] }, + FinancialTransactionClass: { + type: :object, + properties: { + id: { + type: :integer + }, + name: { + type: :string + } + }, + required: %w[id name] + }, Meta: { type: :object, properties: { -- 2.45.2 From 305d1055c41e0fc4eaec2156f23abcf55d4d1782 Mon Sep 17 00:00:00 2001 From: viehlieb Date: Mon, 28 Nov 2022 13:19:50 +0100 Subject: [PATCH 15/46] wip rswagging --- .../api/financial_transaction_classes_spec.rb | 7 +- .../api/financial_transaction_types_spec.rb | 82 ++++++++++++++++++ .../api/financial_transactions_spec.rb | 84 +++++++++++++++++++ spec/swagger_helper.rb | 24 ++++++ 4 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 spec/requests/api/financial_transaction_types_spec.rb create mode 100644 spec/requests/api/financial_transactions_spec.rb diff --git a/spec/requests/api/financial_transaction_classes_spec.rb b/spec/requests/api/financial_transaction_classes_spec.rb index 2b832ea7..b8efd567 100644 --- a/spec/requests/api/financial_transaction_classes_spec.rb +++ b/spec/requests/api/financial_transaction_classes_spec.rb @@ -11,6 +11,7 @@ describe 'Financial Transaction Classes', type: :request do parameter name: "page[size]", in: :query, type: :integer, required: false let!(:financial_transaction_class) { create(:financial_transaction_class) } + response '200', 'success' do schema type: :object, properties: { meta: { @@ -33,7 +34,7 @@ describe 'Financial Transaction Classes', type: :request do end path '/financial_transaction_classes/{id}' do - get 'Retrieves an financial transaction class' do + get 'Retrieves a financial transaction class' do tags 'Category' produces 'application/json' parameter name: :id, in: :path, type: :string @@ -52,7 +53,7 @@ describe 'Financial Transaction Classes', type: :request do end response '401', 'not logged in' do - schema type: :object, properties: { + schema type: :object, properties: { financial_transaction_classes: { type: :array, items: { @@ -61,7 +62,7 @@ describe 'Financial Transaction Classes', type: :request do } } let(:Authorization) { 'abc' } - let(:id) { FinancialTransactionClass.create(name: 'dairy').id } + let(:id) { FinancialTransactionClass.create(name: 'TestTransaction').id } run_test! end diff --git a/spec/requests/api/financial_transaction_types_spec.rb b/spec/requests/api/financial_transaction_types_spec.rb new file mode 100644 index 00000000..3e5efdaa --- /dev/null +++ b/spec/requests/api/financial_transaction_types_spec.rb @@ -0,0 +1,82 @@ +require 'swagger_helper' + +describe 'Financial Transaction types', type: :request do + include ApiHelper + + path '/financial_transaction_types' do + get 'financial transaction types' do + tags 'Category' + produces 'application/json' + parameter name: "page[number]", in: :query, type: :integer, required: false + parameter name: "page[size]", in: :query, type: :integer, required: false + + let!(:financial_transaction_type) { create(:financial_transaction_type) } + response '200', 'success' do + schema type: :object, properties: { + meta: { + '$ref' => '#/components/schemas/pagination' + }, + financial_transaction_type: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransactionType' + } + } + } + + let(:page) { { number: 1, size: 20 } } + run_test! + end + + it_handles_invalid_token + end + end + + path '/financial_transaction_types/{id}' do + get 'Retrieves a financial transaction type' do + tags 'Category' + produces 'application/json' + parameter name: :id, in: :path, type: :string + + response '200', 'financial transaction type found' do + schema type: :object, properties: { + financial_transaction_types: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransactionType' + } + } + } + let(:id) { FinancialTransactionType.create(name: 'TestType').id } + run_test! + end + + response '401', 'not logged in' do + schema type: :object, properties: { + financial_transaction_types: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransactionType' + } + } + } + let(:Authorization) { 'abc' } + let(:id) { FinancialTransactionType.create(name: 'TestType').id } + run_test! + end + + response '404', 'financial transaction type not found' do + schema type: :object, properties: { + financial_transaction_types: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransactionType' + } + } + } + let(:id) { 'invalid' } + run_test! + end + end + end +end diff --git a/spec/requests/api/financial_transactions_spec.rb b/spec/requests/api/financial_transactions_spec.rb new file mode 100644 index 00000000..6c27a9a8 --- /dev/null +++ b/spec/requests/api/financial_transactions_spec.rb @@ -0,0 +1,84 @@ +require 'swagger_helper' + +describe 'Financial Transaction', type: :request do + include ApiHelper + + path '/financial_transactions' do + get 'financial transactions' do + tags 'Financial Transaction' + produces 'application/json' + parameter name: "page[number]", in: :query, type: :integer, required: false + parameter name: "page[size]", in: :query, type: :integer, required: false + + let!(:financial_transaction) { create(:financial_transaction) } + let(:api_scopes) { ['finance:read', 'finance:write'] } + + response '200', 'success' do + schema type: :object, properties: { + meta: { + '$ref' => '#/components/schemas/pagination' + }, + financial_transaction: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransaction' + } + } + } + + let(:page) { { number: 1, size: 20 } } + run_test! + end + + it_handles_invalid_token + end + end + + path '/financial_transactions/{id}' do + get 'Retrieves a financial transaction ' do + tags 'Category' + produces 'application/json' + parameter name: :id, in: :path, type: :string + + response '200', 'financial transaction found' do + schema type: :object, properties: { + financial_transaction: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransaction' + } + } + } + let(:id) { FinancialTransaction.create(user: user).id } + run_test! + end + + response '401', 'not logged in' do + schema type: :object, properties: { + financial_transaction: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransaction' + } + } + } + let(:Authorization) { 'abc' } + let(:id) { FinancialTransaction.create(name: 'TestTransaction').id } + run_test! + end + + response '404', 'financial transaction not found' do + schema type: :object, properties: { + financial_transaction: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransaction' + } + } + } + let(:id) { 'invalid' } + run_test! + end + end + end +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 7fed0c91..5f066aec 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -46,6 +46,18 @@ RSpec.configure do |config| }, required: %w[id name] }, + FinancialTransaction: { + type: :object, + properties: { + id: { + type: :integer + }, + name: { + type: :string + } + }, + required: %w[id financial_transaction_type] + }, FinancialTransactionClass: { type: :object, properties: { @@ -58,6 +70,18 @@ RSpec.configure do |config| }, required: %w[id name] }, + FinancialTransactionType: { + type: :object, + properties: { + id: { + type: :integer + }, + name: { + type: :string + } + }, + required: %w[id name financial_transaction_class] + }, Meta: { type: :object, properties: { -- 2.45.2 From ecf5c6e1d4d67dff36afde7ec02b2b09dcb1a411 Mon Sep 17 00:00:00 2001 From: viehlieb Date: Tue, 29 Nov 2022 18:55:45 +0100 Subject: [PATCH 16/46] rswagged financial_transactions --- .../api/financial_transactions_spec.rb | 41 ++++++++----------- spec/support/api_helper.rb | 24 +++++++++++ spec/swagger_helper.rb | 15 +------ 3 files changed, 42 insertions(+), 38 deletions(-) diff --git a/spec/requests/api/financial_transactions_spec.rb b/spec/requests/api/financial_transactions_spec.rb index 6c27a9a8..84458e79 100644 --- a/spec/requests/api/financial_transactions_spec.rb +++ b/spec/requests/api/financial_transactions_spec.rb @@ -2,21 +2,26 @@ require 'swagger_helper' describe 'Financial Transaction', type: :request do include ApiHelper + let!(:finance_user) { create(:user, groups: [create(:workgroup, role_finance: true)]) } + let!(:api_scopes) { ['finance:read', 'finance:write'] } + let(:api_access_token) { create(:oauth2_access_token, resource_owner_id: finance_user.id, scopes: api_scopes&.join(' ')).token } + let(:financial_transaction) { create(:financial_transaction, user: user) } path '/financial_transactions' do get 'financial transactions' do tags 'Financial Transaction' produces 'application/json' - parameter name: "page[number]", in: :query, type: :integer, required: false - parameter name: "page[size]", in: :query, type: :integer, required: false - - let!(:financial_transaction) { create(:financial_transaction) } - let(:api_scopes) { ['finance:read', 'finance:write'] } + parameter name: "per_page", in: :query, type: :integer, required: false + parameter name: "page", in: :query, type: :integer, required: false response '200', 'success' do schema type: :object, properties: { meta: { - '$ref' => '#/components/schemas/pagination' + type: :object, + items: + { + '$ref': '#/components/schemas/Meta' + } }, financial_transaction: { type: :array, @@ -25,12 +30,11 @@ describe 'Financial Transaction', type: :request do } } } - - let(:page) { { number: 1, size: 20 } } + let(:page) { 1 } + let(:per_page) { 10 } run_test! end - - it_handles_invalid_token + it_handles_invalid_scope end end @@ -52,20 +56,7 @@ describe 'Financial Transaction', type: :request do let(:id) { FinancialTransaction.create(user: user).id } run_test! end - - response '401', 'not logged in' do - schema type: :object, properties: { - financial_transaction: { - type: :array, - items: { - '$ref': '#/components/schemas/FinancialTransaction' - } - } - } - let(:Authorization) { 'abc' } - let(:id) { FinancialTransaction.create(name: 'TestTransaction').id } - run_test! - end + it_handles_invalid_scope_with_id(:financial_transaction) response '404', 'financial transaction not found' do schema type: :object, properties: { @@ -79,6 +70,8 @@ describe 'Financial Transaction', type: :request do let(:id) { 'invalid' } run_test! end + # response 403 + it_handles_invalid_scope_with_id(:financial_transaction) end end end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 5c2246a3..5b97414a 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -18,6 +18,18 @@ module ApiHelper end end + def self.it_handles_invalid_token_with_id(class_sym) + context 'with invalid access token' do + let(:Authorization) { 'abc' } + let(:id) { create(class_sym).id } + + response 401, 'not logged-in' do + schema '$ref' => '#/components/schemas/Error401' + run_test! + end + end + end + def self.it_handles_invalid_scope context 'with invalid scope' do let(:api_scopes) { ['none'] } @@ -29,6 +41,18 @@ module ApiHelper end end + def self.it_handles_invalid_scope_with_id(class_sym) + context 'with invalid scope' do + let(:api_scopes) { ['none'] } + let(:id) { create(class_sym).id } + + response 403, 'missing scope' do + schema '$ref' => '#/components/schemas/Error403' + run_test! + end + end + end + def self.it_handles_invalid_token_and_scope(*args) it_handles_invalid_token(*args) it_handles_invalid_scope(*args) diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 5f066aec..9f1d1f7e 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -24,16 +24,6 @@ RSpec.configure do |config| paths: {}, components: { schemas: { - pagination: { - type: :object, - properties: { - recordCount: { type: :integer }, - pageCount: { type: :integer }, - currentPage: { type: :integer }, - pageSize: { type: :integer } - }, - required: %w(recordCount pageCount currentPage pageSize) - }, ArticleCategory: { type: :object, properties: { @@ -51,12 +41,9 @@ RSpec.configure do |config| properties: { id: { type: :integer - }, - name: { - type: :string } }, - required: %w[id financial_transaction_type] + required: %w[amount note user_id] }, FinancialTransactionClass: { type: :object, -- 2.45.2 From d8b2aa0a112827c6f398339833511491ea77f835 Mon Sep 17 00:00:00 2001 From: viehlieb Date: Tue, 29 Nov 2022 21:37:45 +0100 Subject: [PATCH 17/46] wip user/financial_transactions - first api post test --- spec/app_config.yml | 1 + .../api/user/financial_transactions_spec.rb | 115 ++++++++++++++++++ spec/support/api_helper.rb | 2 +- spec/swagger_helper.rb | 51 ++++++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 spec/requests/api/user/financial_transactions_spec.rb diff --git a/spec/app_config.yml b/spec/app_config.yml index 2e146be9..a9bd72b0 100644 --- a/spec/app_config.yml +++ b/spec/app_config.yml @@ -6,6 +6,7 @@ default: &defaults multi_coop_install: false + use_self_service: true default_scope: 'f' name: FC Minimal diff --git a/spec/requests/api/user/financial_transactions_spec.rb b/spec/requests/api/user/financial_transactions_spec.rb new file mode 100644 index 00000000..699c0347 --- /dev/null +++ b/spec/requests/api/user/financial_transactions_spec.rb @@ -0,0 +1,115 @@ +require 'swagger_helper' + +describe 'User', type: :request do + include ApiHelper + + let(:api_scopes) { ['finance:user'] } + let(:user) { create :user, groups: [create(:ordergroup)] } + let(:other_user2) { create :user } + let(:ft) { create(:financial_transaction, user: user, ordergroup: user.ordergroup) } + + before do + ft + end + + path '/user/financial_transactions' do + post 'financial transaction to create' do + tags 'User', 'FinancialTransaction' + consumes 'application/json' + produces 'application/json' + + parameter name: :financial_transaction, in: :body, schema: { + type: :object, + properties: { + amount: { type: :integer }, + financial_transaction_type: { type: :integer }, + note: { type: :string } } + } + + response '200', 'success' do + schema type: :object, properties: { + financial_transaction_for_create: { + type: :object, + items: { + '$ref': '#/components/schemas/FinancialTransactionForCreate' + } + } + } + let(:financial_transaction) { { amount: 3, financial_transaction_type_id: create(:financial_transaction_type).id, note: 'lirum larum' } } + run_test! + end + end + + get 'financial transactions of the members ordergroup' do + tags 'User', 'Financial Transaction' + produces 'application/json' + + response '200', 'success' do + schema type: :object, properties: { + meta: { + type: :object, + items: + { + '$ref': '#/components/schemas/Meta' + } + }, + financial_transaction: { + type: :array, + items: { + '$ref': '#/components/schemas/FinancialTransaction' + } + } + } + + run_test! do |response| + data = JSON.parse(response.body) + expect(data['financial_transactions'].first['id']).to eq(ft.id) + end + end + # responses 401 & 403 + it_handles_invalid_token_and_scope + end + end + + path '/user/financial_transactions/{id}' do + get 'find financial transaction by id' do + tags 'User', 'FinancialTransaction' + produces 'application/json' + parameter name: :id, in: :path, type: :string + + response '200', 'success' do + schema type: :object, properties: { + financial_transaction: { + type: :object, + items: { + '$ref': '#/components/schemas/FinancialTransaction' + } + } + } + let(:id) { ft.id } + run_test! do |response| + data = JSON.parse(response.body) + expect(data['financial_transaction']['id']).to eq(ft.id) + end + end + + # 401 + it_handles_invalid_token_with_id(:financial_transaction) + # 403 + it_handles_invalid_scope_with_id(:financial_transaction) + # 404 + response '404', 'financial transaction not found' do + schema type: :object, properties: { + financial_transaction: { + type: :object, + items: { + '$ref': '#/components/schemas/FinancialTransaction' + } + } + } + let(:id) { 'invalid' } + run_test! + end + end + end +end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 5b97414a..7780db8a 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -45,7 +45,7 @@ module ApiHelper context 'with invalid scope' do let(:api_scopes) { ['none'] } let(:id) { create(class_sym).id } - + response 403, 'missing scope' do schema '$ref' => '#/components/schemas/Error403' run_test! diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 9f1d1f7e..8c26d089 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -41,6 +41,57 @@ RSpec.configure do |config| properties: { id: { type: :integer + }, + amount: { + type: :integer, + description: 'amount credited (negative for a debit transaction)' + }, + financial_transaction_type_id: + { + type: :integer, + description: 'id of the type of the transaction' + }, + note: { + type: :string, + description: 'note entered with the transaction' + }, + user_id: { + type: :integer, + required: false, + description: 'id of user who entered the transaction (may be null for deleted users or 0 for a system user)' + }, + user_name: { + type: :string, + required: false, + description: 'name of user who entered the transaction (may be null or empty string for deleted users or system users)' + }, + financial_transaction_type_name: { + type: :string, + description: 'name of the type of the transaction' + }, + created_at: { + type: :string, + format: :datetime, + description: 'when the transaction was entered' + } + }, + required: %w[amount note user_id] + }, + FinancialTransactionForCreate: { + type: :object, + properties: { + amount: { + type: :integer, + description: 'amount credited (negative for a debit transaction)' + }, + financial_transaction_type_id: + { + type: :integer, + description: 'id of the type of the transaction' + }, + note: { + type: :string, + description: 'note entered with the transaction' } }, required: %w[amount note user_id] -- 2.45.2 From 92e8a060da79b883d17a0100412945e695d8ac11 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 28 Nov 2022 17:30:20 +0100 Subject: [PATCH 18/46] add order_articles_spec --- spec/api/v1/order_articles_spec.rb | 59 +++++++++++ spec/requests/api/order_articles_spec.rb | 125 +++++++++++++++++++++++ spec/swagger_helper.rb | 89 ++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 spec/api/v1/order_articles_spec.rb create mode 100644 spec/requests/api/order_articles_spec.rb diff --git a/spec/api/v1/order_articles_spec.rb b/spec/api/v1/order_articles_spec.rb new file mode 100644 index 00000000..85249401 --- /dev/null +++ b/spec/api/v1/order_articles_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +# Most routes are tested in the swagger_spec, this tests (non-ransack) parameters. +describe Api::V1::OrderArticlesController, type: :controller do + include ApiOAuth + let(:api_scopes) { ['orders:read'] } + + let(:json_order_articles) { json_response['order_articles'] } + let(:json_order_article_ids) { json_order_articles.map { |joa| joa["id"] } } + + describe "GET :index" do + context "with param q[ordered]" do + let(:order) { create(:order, article_count: 4) } + let(:order_articles) { order.order_articles } + + before do + order_articles[0].update_attributes! quantity: 0, tolerance: 0, units_to_order: 0 + order_articles[1].update_attributes! quantity: 1, tolerance: 0, units_to_order: 0 + order_articles[2].update_attributes! quantity: 0, tolerance: 1, units_to_order: 0 + order_articles[3].update_attributes! quantity: 0, tolerance: 0, units_to_order: 1 + end + + it "(unset)" do + get :index, params: { foodcoop: 'f' } + expect(json_order_articles.count).to eq 4 + end + + it "all" do + get :index, params: { foodcoop: 'f', q: { ordered: 'all' } } + expect(json_order_article_ids).to match_array order_articles[1..2].map(&:id) + end + + it "supplier" do + get :index, params: { foodcoop: 'f', q: { ordered: 'supplier' } } + expect(json_order_article_ids).to match_array [order_articles[3].id] + end + + it "member" do + get :index, params: { foodcoop: 'f', q: { ordered: 'member' } } + expect(json_order_articles.count).to eq 0 + end + + context "when ordered by user" do + let(:user) { create(:user, :ordergroup) } + let(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) } + + before do + create(:group_order_article, group_order: go, order_article: order_articles[1], quantity: 1) + create(:group_order_article, group_order: go, order_article: order_articles[2], tolerance: 0) + end + + it "member" do + get :index, params: { foodcoop: 'f', q: { ordered: 'member' } } + expect(json_order_article_ids).to match_array order_articles[1..2].map(&:id) + end + end + end + end +end diff --git a/spec/requests/api/order_articles_spec.rb b/spec/requests/api/order_articles_spec.rb new file mode 100644 index 00000000..6935fe62 --- /dev/null +++ b/spec/requests/api/order_articles_spec.rb @@ -0,0 +1,125 @@ +require 'swagger_helper' + +describe 'Order Articles', type: :request do + include ApiHelper + + path '/order_articles' do + get 'order articles' do + tags 'Order' + produces 'application/json' + parameter name: 'page[number]', in: :query, type: :integer, required: false + parameter name: 'page[size]', in: :query, type: :integer, required: false + parameter name: 'q', in: :query, required: false, + description: "'member' show articles ordered by the user's ordergroup, 'all' by all members, and 'supplier' ordered at the supplier", + schema: { + type: :object, + ordered: { + type: :string, + enum: %w[member all supplier] + } + } + let(:api_scopes) { ['orders:read', 'orders:write'] } + let(:order) { create(:order, article_count: 4) } + let(:order_articles) { order.order_articles } + + before do + order_articles[0].update_attributes! quantity: 0, tolerance: 0, units_to_order: 0 + order_articles[1].update_attributes! quantity: 1, tolerance: 0, units_to_order: 0 + order_articles[2].update_attributes! quantity: 0, tolerance: 1, units_to_order: 0 + order_articles[3].update_attributes! quantity: 0, tolerance: 0, units_to_order: 1 + end + + response '200', 'success' do + schema type: :object, properties: { + meta: { + '$ref' => '#/components/schemas/Meta' + }, + order_articles: { + type: :array, + items: { + '$ref': '#/components/schemas/OrderArticle' + } + } + } + describe '(unset)' do + run_test! + end + + describe 'all' do + let(:q) { { q: { ordered: 'all' } } } + + run_test! do |response| + json_order_articles = JSON.parse(response.body)['order_articles'] + json_order_article_ids = json_order_articles.map { |d| d['id'].to_i } + expect(json_order_article_ids).to match_array order_articles[1..2].map(&:id) + end + end + + describe 'supplier' do + let(:q) { { q: { ordered: 'supplier' } } } + + run_test! do |response| + json_order_articles = JSON.parse(response.body)['order_articles'] + json_order_article_ids = json_order_articles.map { |d| d['id'].to_i } + expect(json_order_article_ids).to match_array [order_articles[3].id] + end + end + + describe 'member' do + let(:q) { { q: { ordered: 'member' } } } + + run_test! do |response| + json_order_articles = JSON.parse(response.body)['order_articles'] + expect(json_order_articles.count).to eq 0 + end + end + + context 'when ordered by user' do + let(:user) { create(:user, :ordergroup) } + let(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) } + + before do + create(:group_order_article, group_order: go, order_article: order_articles[1], quantity: 1) + create(:group_order_article, group_order: go, order_article: order_articles[2], tolerance: 0) + end + + describe 'member' do + let(:q) { { q: { ordered: 'member' } } } + + run_test! do |response| + json_order_articles = JSON.parse(response.body)['order_articles'] + json_order_article_ids = json_order_articles.map { |d| d['id'].to_i } + expect(json_order_article_ids).to match_array order_articles[1..2].map(&:id) + end + end + end + end + + it_handles_invalid_token_and_scope + end + end + + path '/order_articles/{id}' do + get 'order articles' do + tags 'Order' + produces 'application/json' + parameter name: 'id', in: :path, type: :integer, minimum: 1, required: true + + let(:api_scopes) { ['orders:read', 'orders:write'] } + let(:order) { create(:order, article_count: 1) } + let(:id) { order.order_articles.first.id } + + response '200', 'success' do + schema type: :object, properties: { + order_article: { + '$ref': '#/components/schemas/OrderArticle' + } + } + + run_test! + end + + it_handles_invalid_token_and_scope + end + end +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 8c26d089..080fde20 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -24,6 +24,95 @@ RSpec.configure do |config| paths: {}, components: { schemas: { + pagination: { + type: :object, + properties: { + recordCount: { type: :integer }, + pageCount: { type: :integer }, + currentPage: { type: :integer }, + pageSize: { type: :integer } + }, + required: %w(recordCount pageCount currentPage pageSize) + }, + Article: { + type: :object, + properties: { + id: { + type: :integer + }, + name: { + type: :string + }, + supplier_id: { + type: :integer, + description: 'id of supplier, or 0 for stock articles' + }, + supplier_name: { + type: %w[string null], + description: 'name of the supplier, or null for stock articles' + }, + unit: { + type: :string, + description: 'amount of each unit, e.g. "100 g" or "kg"' + }, + unit_quantity: { + type: :integer, + description: 'units can only be ordered from the supplier in multiples of unit_quantity' + }, + note: { + type: %w[string null], + description: 'generic note' + }, + manufacturer: { + type: %w[string null], + description: 'manufacturer' + }, + origin: { + type: %w[string null], + description: 'origin, preferably (starting with a) 2-letter ISO country code' + }, + article_category_id: { + type: :integer, + description: 'id of article category' + }, + quantity_available: { + type: :integer, + description: 'number of units available (only present on stock articles)' + } + }, + required: %w[id name supplier_id supplier_name unit unit_quantity note manufacturer origin article_category_id] + }, + OrderArticle: { + type: :object, + properties: { + id: { + type: :integer + }, + order_id: { + type: :integer, + description: 'id of order this order article belongs to' + }, + price: { + type: :float, + description: 'foodcoop price' + }, + quantity: { + type: :integer, + description: 'number of units ordered by members' + }, + tolerance: { + type: :integer, + description: 'number of extra units that members are willing to buy to fill a box' + }, + units_to_order: { + type: :integer, + description: 'number of units to order from the supplier' + }, + article: { + '$ref': '#/components/schemas/Article' + } + } + }, ArticleCategory: { type: :object, properties: { -- 2.45.2 From 3c00461f1d18ee630fc9edd44387329cdde0cc29 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 1 Dec 2022 17:57:02 +0100 Subject: [PATCH 19/46] fix swagger violations --- spec/requests/api/user/users_spec.rb | 49 ++++++++++++++++------------ spec/swagger_helper.rb | 11 +++---- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/spec/requests/api/user/users_spec.rb b/spec/requests/api/user/users_spec.rb index 2b6020e9..568c6fb7 100644 --- a/spec/requests/api/user/users_spec.rb +++ b/spec/requests/api/user/users_spec.rb @@ -52,35 +52,42 @@ describe 'User', type: :request do get 'financial summary about the currently logged-in user' do tags 'User', 'FinancialTransaction' produces 'application/json' - let!(:user) { create :user, :ordergroup } + let(:user) { create :user, :ordergroup } + FinancialTransactionClass.create(name: 'TestTransaction') response 200, 'success' do schema type: :object, properties: { - account_balance: { - type: :number, - description: 'booked accout balance of ordergroup' - }, - available_funds: { - type: :number, - description: 'fund available to order articles' - }, - financial_transaction_class_sums: { + financial_overview: { type: :object, properties: { - id: { - type: :integer, - description: 'id of the financial transaction class' - }, - name: { - type: :string, - description: 'name of the financial transaction class' - }, - amount: { + + account_balance: { type: :number, - description: 'sum of the amounts belonging to the financial transaction class' + description: 'booked accout balance of ordergroup' }, - required: %w[id name amount] + available_funds: { + type: :number, + description: 'fund available to order articles' + }, + financial_transaction_class_sums: { + type: :array, + properties: { + id: { + type: :integer, + description: 'id of the financial transaction class' + }, + name: { + type: :string, + description: 'name of the financial transaction class' + }, + amount: { + type: :number, + description: 'sum of the amounts belonging to the financial transaction class' + } + }, + required: %w[id name amount] + } }, required: %w[account_balance available_funds financial_transaction_class_sums] } diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 080fde20..600f45fd 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -93,7 +93,8 @@ RSpec.configure do |config| description: 'id of order this order article belongs to' }, price: { - type: :float, + type: :number, + format: :float, description: 'foodcoop price' }, quantity: { @@ -146,12 +147,10 @@ RSpec.configure do |config| }, user_id: { type: :integer, - required: false, description: 'id of user who entered the transaction (may be null for deleted users or 0 for a system user)' }, user_name: { type: :string, - required: false, description: 'name of user who entered the transaction (may be null or empty string for deleted users or system users)' }, financial_transaction_type_name: { @@ -227,9 +226,9 @@ RSpec.configure do |config| total_count: { type: :integer, description: 'total number of items in the collection' - }, - required: %w[page per_page total_pages total_count] - } + } + }, + required: %w[page per_page total_pages total_count] }, Navigation: { type: :array, -- 2.45.2 From ab26520f7a574da275d3e3def45edff7d95bac66 Mon Sep 17 00:00:00 2001 From: viehlieb Date: Fri, 2 Dec 2022 16:37:54 +0100 Subject: [PATCH 20/46] user/group_order_articles rswagged - wipfinancial_transactions --- .../api/user/financial_transactions_spec.rb | 35 ++- .../api/user/group_order_articles_spec.rb | 259 ++++++++++++++++++ spec/swagger_helper.rb | 50 +++- 3 files changed, 341 insertions(+), 3 deletions(-) create mode 100644 spec/requests/api/user/group_order_articles_spec.rb diff --git a/spec/requests/api/user/financial_transactions_spec.rb b/spec/requests/api/user/financial_transactions_spec.rb index 699c0347..ebbd522f 100644 --- a/spec/requests/api/user/financial_transactions_spec.rb +++ b/spec/requests/api/user/financial_transactions_spec.rb @@ -23,8 +23,10 @@ describe 'User', type: :request do properties: { amount: { type: :integer }, financial_transaction_type: { type: :integer }, - note: { type: :string } } + note: { type: :string } + } } + let(:financial_transaction) { { amount: 3, financial_transaction_type_id: create(:financial_transaction_type).id, note: 'lirum larum' } } response '200', 'success' do schema type: :object, properties: { @@ -35,9 +37,38 @@ describe 'User', type: :request do } } } - let(:financial_transaction) { { amount: 3, financial_transaction_type_id: create(:financial_transaction_type).id, note: 'lirum larum' } } run_test! end + + # 401 + it_handles_invalid_token_with_id(:financial_transaction) + + # 403 + # description: user has no ordergroup, is below minimum balance, self service is disabled, or missing scope + it_handles_invalid_scope_with_id(:financial_transaction) + + # TODO: fix 404 and 422 + # 404 + # Type not found + # description: financial transaction type not found + # Should be 404, but is 200 with validation errors.. + # Rswag::Specs::UnexpectedResponse: + # Expected response code '404' to match '200' + # Response body: {"error":"not_found","error_description":"Couldn't find FinancialTransactionType with 'id'=invalid"} + # let(:financial_transaction) { { amount: 3, financial_transaction_type_id: 'invalid', note: 'lirum larum' } } + # response '404', 'invalid parameter value' do + # schema '$ref' => '#/components/schemas/Error404' + # run_test! + # end + + # 422 + # response '422', 'invalid parameter value' do + # let(:financial_transaction) { { amount: -3, financial_transaction_type_id: create(:financial_transaction_type).id, note: -2 } } + + # schema '$ref' => '#/components/schemas/Error422' + # run_test! + # end + end get 'financial transactions of the members ordergroup' do diff --git a/spec/requests/api/user/group_order_articles_spec.rb b/spec/requests/api/user/group_order_articles_spec.rb new file mode 100644 index 00000000..c2d44793 --- /dev/null +++ b/spec/requests/api/user/group_order_articles_spec.rb @@ -0,0 +1,259 @@ +require 'swagger_helper' + +describe 'User', type: :request do + include ApiHelper + + let(:api_scopes) { ['group_orders:user'] } + let(:user) { create :user, groups: [create(:ordergroup)] } + let(:other_user2) { create :user } + let(:order) { create(:order, article_count: 4) } + let(:order_articles) { order.order_articles } + let(:group_order) { create :group_order, ordergroup: user.ordergroup, order_id: order.id } + let(:goa) { create :group_order_article, group_order: group_order, order_article: order_articles.first } + + before do + goa + end + + path '/user/group_order_articles' do + post 'group order article to create' do + tags 'User', 'Order' + consumes 'application/json' + produces 'application/json' + parameter name: :group_order_article, in: :body, schema: { + type: :object, + properties: { + order_article_id: { type: :integer }, + quantity: { type: :integer }, + tolerance: { type: :string } + } + } + + let(:group_order_article) { { order_article_id: order_articles.last.id, quantity: 1, tolerance: 2 } } + response '200', 'success' do + schema type: :object, properties: { + group_order_article_for_create: { + type: :object, + items: { + '$ref': '#/components/schemas/GroupOrderArticleForCreate' + } + } + } + run_test! + end + + # 401 + it_handles_invalid_token_with_id(:group_order_article) + + # 403 + # description: user has no ordergroup, is below minimum balance, self service is disabled, or missing scope + it_handles_invalid_scope_with_id(:group_order_article) + + # 404 + response '404', 'order article not found in open orders' do + let(:group_order_article) { { order_article_id: 'invalid', quantity: 1, tolerance: 2 } } + schema '$ref' => '#/components/schemas/Error404' + run_test! + end + + # 422 + response '422', 'invalid parameter value' do + let(:group_order_article) { { order_article_id: goa.order_article_id, quantity: 1, tolerance: 2 } } + schema '$ref' => '#/components/schemas/Error422' + run_test! + end + end + + get 'group order articles of the members ordergroup' do + tags 'User', 'Order' + produces 'application/json' + + response '200', 'success' do + schema type: :object, properties: { + meta: { + type: :object, + items: + { + '$ref': '#/components/schemas/Meta' + } + }, + group_order_article: { + type: :array, + items: { + '$ref': '#/components/schemas/GroupOrderArticle' + } + } + } + + run_test! do |response| + data = JSON.parse(response.body) + expect(data['group_order_articles'].first['id']).to eq(goa.id) + end + end + # responses 401 & 403 + it_handles_invalid_token_and_scope + end + end + + path '/user/group_order_articles/{id}' do + patch 'summary: update a group order article (but delete if quantity and tolerance are zero)' do + tags 'User', 'GroupOrderArticle' + consumes 'application/json' + produces 'application/json' + parameter name: :id, in: :path, type: :string + + parameter name: :group_order_article, in: :body, schema: { + type: :object, + properties: { + order_article_id: { type: :integer }, + quantity: { type: :integer }, + tolerance: { type: :integer } + } + } + let(:id) { goa.id } + let(:group_order_article) { { order_article_id: goa.order_article_id, quantity: 2, tolerance: 2 } } + + response '200', 'success' do + schema type: :object, properties: { + group_order_article_for_create: { + type: :object, + items: { + '$ref': '#/components/schemas/GroupOrderArticleForUpdate' + } + } + } + run_test! + end + # 401 + response 401, 'missing token' do + let(:Authorization) { 'abc' } + schema '$ref' => '#/components/schemas/Error401' + run_test! + end + # 403 + response 403, 'missing scope' do + let(:api_scopes) { ['none'] } + schema '$ref' => '#/components/schemas/Error403' + run_test! + end + # 404 + response '404', 'group order article not found' do + schema type: :object, properties: { + group_order_article: { + type: :object, + items: { + '$ref': '#/components/schemas/GroupOrderArticle' + } + } + } + let(:id) { 'invalid' } + run_test! + end + + #422 + response '422', 'invalid parameter value' do + let(:group_order_article) { { order_article_id: 'invalid', quantity: -5, tolerance: 'invalid' } } + schema '$ref' => '#/components/schemas/Error422' + run_test! + end + end + + get 'find group order article by id' do + tags 'User', 'GroupOrderArticle' + produces 'application/json' + parameter name: :id, in: :path, type: :string + + let(:id) { goa.id } + response '200', 'success' do + schema type: :object, properties: { + group_order_article: { + type: :object, + items: { + '$ref': '#/components/schemas/GroupOrderArticle' + } + } + } + run_test! do |response| + data = JSON.parse(response.body) + expect(data['group_order_article']['id']).to eq(goa.id) + end + end + + # 401 + response 401, 'missing token' do + let(:Authorization) { 'abc' } + schema '$ref' => '#/components/schemas/Error401' + run_test! + end + # 403 + response 403, 'missing scope' do + let(:api_scopes) { ['none'] } + schema '$ref' => '#/components/schemas/Error403' + run_test! + end + # 404 + response '404', 'group order article not found' do + schema type: :object, properties: { + group_order_article: { + type: :object, + items: { + '$ref': '#/components/schemas/GroupOrderArticle' + } + } + } + let(:id) { 'invalid' } + run_test! + end + end + + delete 'remove group order article' do + tags 'User', 'Order' + consumes 'application/json' + produces 'application/json' + let(:api_scopes) { ['group_orders:user'] } + + parameter name: :id, in: :path, type: :string + + let(:id) { goa.id } + response '200', 'success' do + schema type: :object, properties: { + group_order_article: { + type: :object, + items: { + '$ref': '#/components/schemas/GroupOrderArticle' + } + } + } + run_test! + end + + # 401 + response 401, 'missing token' do + let(:Authorization) { 'abc' } + schema '$ref' => '#/components/schemas/Error401' + run_test! + end + + # 403 + response 403, 'missing scope' do + let(:api_scopes) { ['none'] } + schema '$ref' => '#/components/schemas/Error403' + run_test! + end + + # 404 + response '404', 'group order article not found' do + schema type: :object, properties: { + group_order_article: { + type: :object, + items: { + '$ref': '#/components/schemas/GroupOrderArticle' + } + } + } + let(:id) { 'invalid' } + run_test! + end + end + end +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 600f45fd..2d255a91 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -208,6 +208,54 @@ RSpec.configure do |config| }, required: %w[id name financial_transaction_class] }, + GroupOrderArticleForUpdate: { + type: :object, + properties: { + quantity: + { + type: :integer, + description: 'number of units ordered by the users ordergroup' + }, + tolerance: + { + type: :integer, + description: 'number of extra units the users ordergroup is willing to buy for filling a box' + } + } + }, + GroupOrderArticleForCreate: { + type: :object, + properties: { + order_article_id: + { + type: :integer, + description: 'id of order article' + } + } + }, + GroupOrderArticle: { + type: :object, + properties: { + id: { + type: :integer + }, + result: { + type: :float, + description: 'number of units the users ordergroup will receive or has received' + }, + total_price: + { + type: :float, + description: 'total price of this group order article' + }, + order_article_id: + { + type: :integer, + description: 'id of order article' + } + }, + required: %w[order_article_id] + }, Meta: { type: :object, properties: { @@ -305,7 +353,7 @@ RSpec.configure do |config| properties: { error: { type: :string, - description: 'unprocessable entity' + description: 'unprocessable entity' }, error_description: { '$ref': '#/components/schemas/Error/properties/error_description' -- 2.45.2 From be4f4d6c138f4c6c6f73d3b0a5a7f273f319485c Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 1 Dec 2022 18:45:18 +0100 Subject: [PATCH 21/46] add orders spec --- spec/requests/api/orders_spec.rb | 55 ++++++++++++++++++++++++++++++++ spec/swagger_helper.rb | 40 +++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 spec/requests/api/orders_spec.rb diff --git a/spec/requests/api/orders_spec.rb b/spec/requests/api/orders_spec.rb new file mode 100644 index 00000000..f6ecb0e1 --- /dev/null +++ b/spec/requests/api/orders_spec.rb @@ -0,0 +1,55 @@ +require 'swagger_helper' + +describe 'Orders', type: :request do + include ApiHelper + let(:api_scopes) { ['orders:read'] } + + path '/orders' do + get 'orders' do + tags 'Order' + produces 'application/json' + parameter name: 'page[number]', in: :query, type: :integer, required: false + parameter name: 'page[size]', in: :query, type: :integer, required: false + + let(:order) { create(:order) } + + response '200', 'success' do + schema type: :object, properties: { + meta: { + '$ref' => '#/components/schemas/Meta' + }, + ordes: { + type: :array, + items: { + '$ref': '#/components/schemas/Order' + } + } + } + + run_test! + end + + it_handles_invalid_token_and_scope + end + end + + path '/orders/{id}' do + get 'Order' do + tags 'Order' + produces 'application/json' + parameter name: 'id', in: :path, type: :integer, minimum: 1, required: true + let(:order) { create(:order) } + let(:id) { order.id } + + response '200', 'success' do + schema type: :object, properties: { + '$ref': '#/components/schemas/Order' + } + + run_test! do |response| + expect(JSON.parse(response.body)['order']['id']).to eq order.id + end + end + end + end +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 2d255a91..0eeb05ac 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -34,6 +34,46 @@ RSpec.configure do |config| }, required: %w(recordCount pageCount currentPage pageSize) }, + Order: { + type: :object, + properties: { + id: { + type: :integer + }, + name: { + type: :string, + description: "name of the order's supplier (or stock)" + }, + starts: { + type: :string, + format: 'date-time', + description: 'when the order was opened' + }, + ends: { + type: ['string', 'null'], + format: 'date-time', + description: 'when the order will close or was closed' + }, + boxfill: { + type: ['string', 'null'], + format: 'date-time', + description: 'when the order will enter or entered the boxfill phase' + }, + pickup: { + type: ['string', 'null'], + format: :date, + description: 'pickup date' + }, + is_open: { + type: :boolean, + description: 'if the order is currently open or not' + }, + is_boxfill: { + type: :boolean, + description: 'if the order is currently in the boxfill phase or not' + } + } + }, Article: { type: :object, properties: { -- 2.45.2 From af6e06dfe7842c19e57001c4b50fdb88ea2b0442 Mon Sep 17 00:00:00 2001 From: viehlieb Date: Mon, 5 Dec 2022 17:07:10 +0100 Subject: [PATCH 22/46] page/per_pagefor each controller, some summaries/descriptions updated --- spec/requests/api/article_categories_spec.rb | 22 +- .../api/financial_transaction_classes_spec.rb | 13 +- .../api/financial_transaction_types_spec.rb | 16 +- .../api/financial_transactions_spec.rb | 4 +- spec/requests/api/order_articles_spec.rb | 6 +- spec/requests/api/orders_spec.rb | 6 +- .../api/user/financial_transactions_spec.rb | 15 +- .../api/user/group_order_articles_spec.rb | 214 +++++++++--------- spec/support/api_helper.rb | 25 +- 9 files changed, 165 insertions(+), 156 deletions(-) diff --git a/spec/requests/api/article_categories_spec.rb b/spec/requests/api/article_categories_spec.rb index c16a0a99..afdcfae2 100644 --- a/spec/requests/api/article_categories_spec.rb +++ b/spec/requests/api/article_categories_spec.rb @@ -7,18 +7,16 @@ describe 'Article Categories', type: :request do get 'article categories' do tags 'Category' produces 'application/json' - parameter name: "page[number]", in: :query, type: :integer, required: false - parameter name: "page[size]", in: :query, type: :integer, required: false - - let!(:order_article) { create(:order, article_count: 1).order_articles.first } - let!(:stock_article) { create(:stock_article) } - let!(:stock_order_article) { create(:stock_order, article_ids: [stock_article.id]).order_articles.first } + parameter name: "per_page", in: :query, type: :integer, required: false + parameter name: "page", in: :query, type: :integer, required: false + let(:page) { 1 } + let(:per_page) { 10 } + let(:order_article) { create(:order, article_count: 1).order_articles.first } + let(:stock_article) { create(:stock_article) } + let(:stock_order_article) { create(:stock_order, article_ids: [stock_article.id]).order_articles.first } response '200', 'success' do schema type: :object, properties: { - meta: { - '$ref' => '#/components/schemas/pagination' - }, article_categories: { type: :array, items: { @@ -26,8 +24,6 @@ describe 'Article Categories', type: :request do } } } - - let(:page) { { number: 1, size: 20 } } run_test! end @@ -36,7 +32,7 @@ describe 'Article Categories', type: :request do end path '/article_categories/{id}' do - get 'Retrieves an article category' do + get 'find article category by id' do tags 'Category' produces 'application/json' parameter name: :id, in: :path, type: :string @@ -82,4 +78,4 @@ describe 'Article Categories', type: :request do end end end -end \ No newline at end of file +end diff --git a/spec/requests/api/financial_transaction_classes_spec.rb b/spec/requests/api/financial_transaction_classes_spec.rb index b8efd567..b016b8dd 100644 --- a/spec/requests/api/financial_transaction_classes_spec.rb +++ b/spec/requests/api/financial_transaction_classes_spec.rb @@ -7,16 +7,16 @@ describe 'Financial Transaction Classes', type: :request do get 'financial transaction classes' do tags 'Category' produces 'application/json' - parameter name: "page[number]", in: :query, type: :integer, required: false - parameter name: "page[size]", in: :query, type: :integer, required: false - let!(:financial_transaction_class) { create(:financial_transaction_class) } + parameter name: "per_page", in: :query, type: :integer, required: false + parameter name: "page", in: :query, type: :integer, required: false + let(:page) { 1 } + let(:per_page) { 10 } + + let(:financial_transaction_class) { create(:financial_transaction_class) } response '200', 'success' do schema type: :object, properties: { - meta: { - '$ref' => '#/components/schemas/pagination' - }, financial_transaction_class: { type: :array, items: { @@ -25,7 +25,6 @@ describe 'Financial Transaction Classes', type: :request do } } - let(:page) { { number: 1, size: 20 } } run_test! end diff --git a/spec/requests/api/financial_transaction_types_spec.rb b/spec/requests/api/financial_transaction_types_spec.rb index 3e5efdaa..68eda4da 100644 --- a/spec/requests/api/financial_transaction_types_spec.rb +++ b/spec/requests/api/financial_transaction_types_spec.rb @@ -7,15 +7,13 @@ describe 'Financial Transaction types', type: :request do get 'financial transaction types' do tags 'Category' produces 'application/json' - parameter name: "page[number]", in: :query, type: :integer, required: false - parameter name: "page[size]", in: :query, type: :integer, required: false - - let!(:financial_transaction_type) { create(:financial_transaction_type) } + parameter name: "per_page", in: :query, type: :integer, required: false + parameter name: "page", in: :query, type: :integer, required: false + let(:page) { 1 } + let(:per_page) { 10 } + let(:financial_transaction_type) { create(:financial_transaction_type) } response '200', 'success' do schema type: :object, properties: { - meta: { - '$ref' => '#/components/schemas/pagination' - }, financial_transaction_type: { type: :array, items: { @@ -23,8 +21,6 @@ describe 'Financial Transaction types', type: :request do } } } - - let(:page) { { number: 1, size: 20 } } run_test! end @@ -33,7 +29,7 @@ describe 'Financial Transaction types', type: :request do end path '/financial_transaction_types/{id}' do - get 'Retrieves a financial transaction type' do + get 'find financial transaction type by id' do tags 'Category' produces 'application/json' parameter name: :id, in: :path, type: :string diff --git a/spec/requests/api/financial_transactions_spec.rb b/spec/requests/api/financial_transactions_spec.rb index 84458e79..ce396a6e 100644 --- a/spec/requests/api/financial_transactions_spec.rb +++ b/spec/requests/api/financial_transactions_spec.rb @@ -56,7 +56,7 @@ describe 'Financial Transaction', type: :request do let(:id) { FinancialTransaction.create(user: user).id } run_test! end - it_handles_invalid_scope_with_id(:financial_transaction) + it_handles_invalid_scope_with_id(:financial_transaction, 'missing scope or no permission') response '404', 'financial transaction not found' do schema type: :object, properties: { @@ -71,7 +71,7 @@ describe 'Financial Transaction', type: :request do run_test! end # response 403 - it_handles_invalid_scope_with_id(:financial_transaction) + it_handles_invalid_scope_with_id(:financial_transaction, 'missing scope or no permission') end end end diff --git a/spec/requests/api/order_articles_spec.rb b/spec/requests/api/order_articles_spec.rb index 6935fe62..304869e3 100644 --- a/spec/requests/api/order_articles_spec.rb +++ b/spec/requests/api/order_articles_spec.rb @@ -7,8 +7,10 @@ describe 'Order Articles', type: :request do get 'order articles' do tags 'Order' produces 'application/json' - parameter name: 'page[number]', in: :query, type: :integer, required: false - parameter name: 'page[size]', in: :query, type: :integer, required: false + parameter name: "per_page", in: :query, type: :integer, required: false + parameter name: "page", in: :query, type: :integer, required: false + let(:page) { 1 } + let(:per_page) { 10 } parameter name: 'q', in: :query, required: false, description: "'member' show articles ordered by the user's ordergroup, 'all' by all members, and 'supplier' ordered at the supplier", schema: { diff --git a/spec/requests/api/orders_spec.rb b/spec/requests/api/orders_spec.rb index f6ecb0e1..43f546a3 100644 --- a/spec/requests/api/orders_spec.rb +++ b/spec/requests/api/orders_spec.rb @@ -8,8 +8,10 @@ describe 'Orders', type: :request do get 'orders' do tags 'Order' produces 'application/json' - parameter name: 'page[number]', in: :query, type: :integer, required: false - parameter name: 'page[size]', in: :query, type: :integer, required: false + parameter name: "per_page", in: :query, type: :integer, required: false + parameter name: "page", in: :query, type: :integer, required: false + let(:page) { 1 } + let(:per_page) { 20 } let(:order) { create(:order) } diff --git a/spec/requests/api/user/financial_transactions_spec.rb b/spec/requests/api/user/financial_transactions_spec.rb index ebbd522f..f3ceebb6 100644 --- a/spec/requests/api/user/financial_transactions_spec.rb +++ b/spec/requests/api/user/financial_transactions_spec.rb @@ -13,11 +13,14 @@ describe 'User', type: :request do end path '/user/financial_transactions' do - post 'financial transaction to create' do + post 'create new financial transaction (requires enabled self service)' do tags 'User', 'FinancialTransaction' consumes 'application/json' produces 'application/json' - + parameter name: "per_page", in: :query, type: :integer, required: false + parameter name: "page", in: :query, type: :integer, required: false + let(:page) { 1 } + let(:per_page) { 20 } parameter name: :financial_transaction, in: :body, schema: { type: :object, properties: { @@ -45,7 +48,7 @@ describe 'User', type: :request do # 403 # description: user has no ordergroup, is below minimum balance, self service is disabled, or missing scope - it_handles_invalid_scope_with_id(:financial_transaction) + it_handles_invalid_scope_with_id(:financial_transaction, 'user has no ordergroup, is below minimum balance, self service is disabled, or missing scope') # TODO: fix 404 and 422 # 404 @@ -68,10 +71,8 @@ describe 'User', type: :request do # schema '$ref' => '#/components/schemas/Error422' # run_test! # end - end - - get 'financial transactions of the members ordergroup' do + get "financial transactions of the member's ordergroup" do tags 'User', 'Financial Transaction' produces 'application/json' @@ -127,7 +128,7 @@ describe 'User', type: :request do # 401 it_handles_invalid_token_with_id(:financial_transaction) # 403 - it_handles_invalid_scope_with_id(:financial_transaction) + it_handles_invalid_scope_with_id(:financial_transaction, 'user has no ordergroup or missing scope') # 404 response '404', 'financial transaction not found' do schema type: :object, properties: { diff --git a/spec/requests/api/user/group_order_articles_spec.rb b/spec/requests/api/user/group_order_articles_spec.rb index c2d44793..55e44dd1 100644 --- a/spec/requests/api/user/group_order_articles_spec.rb +++ b/spec/requests/api/user/group_order_articles_spec.rb @@ -16,58 +16,13 @@ describe 'User', type: :request do end path '/user/group_order_articles' do - post 'group order article to create' do - tags 'User', 'Order' - consumes 'application/json' - produces 'application/json' - parameter name: :group_order_article, in: :body, schema: { - type: :object, - properties: { - order_article_id: { type: :integer }, - quantity: { type: :integer }, - tolerance: { type: :string } - } - } - - let(:group_order_article) { { order_article_id: order_articles.last.id, quantity: 1, tolerance: 2 } } - response '200', 'success' do - schema type: :object, properties: { - group_order_article_for_create: { - type: :object, - items: { - '$ref': '#/components/schemas/GroupOrderArticleForCreate' - } - } - } - run_test! - end - - # 401 - it_handles_invalid_token_with_id(:group_order_article) - - # 403 - # description: user has no ordergroup, is below minimum balance, self service is disabled, or missing scope - it_handles_invalid_scope_with_id(:group_order_article) - - # 404 - response '404', 'order article not found in open orders' do - let(:group_order_article) { { order_article_id: 'invalid', quantity: 1, tolerance: 2 } } - schema '$ref' => '#/components/schemas/Error404' - run_test! - end - - # 422 - response '422', 'invalid parameter value' do - let(:group_order_article) { { order_article_id: goa.order_article_id, quantity: 1, tolerance: 2 } } - schema '$ref' => '#/components/schemas/Error422' - run_test! - end - end - - get 'group order articles of the members ordergroup' do + get 'group order articles' do tags 'User', 'Order' produces 'application/json' - + parameter name: "per_page", in: :query, type: :integer, required: false + parameter name: "page", in: :query, type: :integer, required: false + let(:page) { 1 } + let(:per_page) { 20 } response '200', 'success' do schema type: :object, properties: { meta: { @@ -90,74 +45,65 @@ describe 'User', type: :request do expect(data['group_order_articles'].first['id']).to eq(goa.id) end end - # responses 401 & 403 - it_handles_invalid_token_and_scope - end - end - path '/user/group_order_articles/{id}' do - patch 'summary: update a group order article (but delete if quantity and tolerance are zero)' do - tags 'User', 'GroupOrderArticle' + # response 401 + it_handles_invalid_token + + # response 403 + it_handles_invalid_scope('user has no ordergroup or missing scope') + end + post 'create new group order article' do + tags 'User', 'Order' consumes 'application/json' produces 'application/json' - parameter name: :id, in: :path, type: :string - parameter name: :group_order_article, in: :body, schema: { type: :object, + description: 'group order article to create', properties: { order_article_id: { type: :integer }, quantity: { type: :integer }, - tolerance: { type: :integer } - } + tolerance: { type: :string } + }, + required: true } - let(:id) { goa.id } - let(:group_order_article) { { order_article_id: goa.order_article_id, quantity: 2, tolerance: 2 } } + let(:group_order_article) { { order_article_id: order_articles.last.id, quantity: 1, tolerance: 2 } } response '200', 'success' do schema type: :object, properties: { group_order_article_for_create: { type: :object, items: { - '$ref': '#/components/schemas/GroupOrderArticleForUpdate' + '$ref': '#/components/schemas/GroupOrderArticleForCreate' } } } run_test! end - # 401 - response 401, 'missing token' do - let(:Authorization) { 'abc' } - schema '$ref' => '#/components/schemas/Error401' - run_test! - end - # 403 - response 403, 'missing scope' do - let(:api_scopes) { ['none'] } - schema '$ref' => '#/components/schemas/Error403' - run_test! - end - # 404 - response '404', 'group order article not found' do - schema type: :object, properties: { - group_order_article: { - type: :object, - items: { - '$ref': '#/components/schemas/GroupOrderArticle' - } - } - } - let(:id) { 'invalid' } - run_test! - end - #422 - response '422', 'invalid parameter value' do - let(:group_order_article) { { order_article_id: 'invalid', quantity: -5, tolerance: 'invalid' } } + # 401 + it_handles_invalid_token_with_id(:group_order_article) + + # 403 + # description: user has no ordergroup, is below minimum balance, self service is disabled, or missing scope + it_handles_invalid_scope_with_id(:group_order_article, 'user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope') + + # 404 + response '404', 'order article not found in open orders' do + let(:group_order_article) { { order_article_id: 'invalid', quantity: 1, tolerance: 2 } } + schema '$ref' => '#/components/schemas/Error404' + run_test! + end + + # 422 + response '422', 'invalid parameter value or group order article already exists' do + let(:group_order_article) { { order_article_id: goa.order_article_id, quantity: 1, tolerance: 2 } } schema '$ref' => '#/components/schemas/Error422' run_test! end end + end + path '/user/group_order_articles/{id}' do get 'find group order article by id' do tags 'User', 'GroupOrderArticle' produces 'application/json' @@ -180,13 +126,13 @@ describe 'User', type: :request do end # 401 - response 401, 'missing token' do + response 401, 'not logged-in' do let(:Authorization) { 'abc' } schema '$ref' => '#/components/schemas/Error401' run_test! end # 403 - response 403, 'missing scope' do + response 403, 'user has no ordergroup or missing scope' do let(:api_scopes) { ['none'] } schema '$ref' => '#/components/schemas/Error403' run_test! @@ -205,6 +151,69 @@ describe 'User', type: :request do run_test! end end + patch 'update a group order article (but delete if quantity and tolerance are zero)' do + tags 'User', 'GroupOrderArticle' + consumes 'application/json' + produces 'application/json' + parameter name: :id, in: :path, type: :string + + parameter name: :group_order_article, in: :body, schema: { + type: :object, + description: 'group order article to create', + properties: { + order_article_id: { type: :integer }, + quantity: { type: :integer }, + tolerance: { type: :string } + }, + required: true + } + let(:id) { goa.id } + let(:group_order_article) { { order_article_id: goa.order_article_id, quantity: 2, tolerance: 2 } } + + response '200', 'success' do + schema type: :object, properties: { + group_order_article_for_create: { + type: :object, + items: { + '$ref': '#/components/schemas/GroupOrderArticleForUpdate' + } + } + } + run_test! + end + # 401 + response 401, 'not logged-in' do + let(:Authorization) { 'abc' } + schema '$ref' => '#/components/schemas/Error401' + run_test! + end + # 403 + response 403, 'user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope' do + let(:api_scopes) { ['none'] } + schema '$ref' => '#/components/schemas/Error403' + run_test! + end + # 404 + response '404', 'order article not found in open orders' do + schema type: :object, properties: { + group_order_article: { + type: :object, + items: { + '$ref': '#/components/schemas/GroupOrderArticle' + } + } + } + let(:id) { 'invalid' } + run_test! + end + + # 422 + response '422', 'invalid parameter value' do + let(:group_order_article) { { order_article_id: 'invalid', quantity: -5, tolerance: 'invalid' } } + schema '$ref' => '#/components/schemas/Error422' + run_test! + end + end delete 'remove group order article' do tags 'User', 'Order' @@ -228,32 +237,21 @@ describe 'User', type: :request do end # 401 - response 401, 'missing token' do + response 401, 'not logged-in' do let(:Authorization) { 'abc' } schema '$ref' => '#/components/schemas/Error401' run_test! end # 403 - response 403, 'missing scope' do + response 403, 'user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope' do let(:api_scopes) { ['none'] } schema '$ref' => '#/components/schemas/Error403' run_test! end # 404 - response '404', 'group order article not found' do - schema type: :object, properties: { - group_order_article: { - type: :object, - items: { - '$ref': '#/components/schemas/GroupOrderArticle' - } - } - } - let(:id) { 'invalid' } - run_test! - end + it_cannot_find_object('order article not found in open orders') end end end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 7780db8a..176e9e21 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -30,29 +30,44 @@ module ApiHelper end end - def self.it_handles_invalid_scope + def self.it_handles_invalid_scope(description="missing scope") context 'with invalid scope' do let(:api_scopes) { ['none'] } - response 403, 'missing scope' do + response 403, description do schema '$ref' => '#/components/schemas/Error403' run_test! end end end - def self.it_handles_invalid_scope_with_id(class_sym) + def self.it_handles_invalid_scope_with_id(class_sym, description) context 'with invalid scope' do let(:api_scopes) { ['none'] } let(:id) { create(class_sym).id } - - response 403, 'missing scope' do + response 403, description do schema '$ref' => '#/components/schemas/Error403' run_test! end end end + def self.it_cannot_find_object(description="not found") + # 404 + response '404', description do + schema type: :object, properties: { + group_order_article: { + type: :object, + items: { + '$ref': '#/components/schemas/GroupOrderArticle' + } + } + } + let(:id) { 'invalid' } + run_test! + end + end + def self.it_handles_invalid_token_and_scope(*args) it_handles_invalid_token(*args) it_handles_invalid_scope(*args) -- 2.45.2 From ccff79b0416cdacc9e18de6fa0f3d9c0a8555844 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 11:30:09 +0100 Subject: [PATCH 23/46] fix: article categories and 404 helper --- spec/requests/api/article_categories_spec.rb | 33 +--- spec/support/api_helper.rb | 21 +-- swagger/v1/swagger.yaml | 169 ------------------- 3 files changed, 11 insertions(+), 212 deletions(-) delete mode 100644 swagger/v1/swagger.yaml diff --git a/spec/requests/api/article_categories_spec.rb b/spec/requests/api/article_categories_spec.rb index afdcfae2..68467241 100644 --- a/spec/requests/api/article_categories_spec.rb +++ b/spec/requests/api/article_categories_spec.rb @@ -9,8 +9,6 @@ describe 'Article Categories', type: :request do produces 'application/json' parameter name: "per_page", in: :query, type: :integer, required: false parameter name: "page", in: :query, type: :integer, required: false - let(:page) { 1 } - let(:per_page) { 10 } let(:order_article) { create(:order, article_count: 1).order_articles.first } let(:stock_article) { create(:stock_article) } let(:stock_order_article) { create(:stock_order, article_ids: [stock_article.id]).order_articles.first } @@ -46,36 +44,11 @@ describe 'Article Categories', type: :request do } } } - let(:id) { ArticleCategory.create(name: 'dairy').id } - run_test! - end - - response '401', 'not logged in' do - schema type: :object, properties: { - article_categories: { - type: :array, - items: { - '$ref': '#/components/schemas/ArticleCategory' - } - } - } - let(:Authorization) { 'abc' } - let(:id) { ArticleCategory.create(name: 'dairy').id } - run_test! - end - - response '404', 'article category not found' do - schema type: :object, properties: { - article_categories: { - type: :array, - items: { - '$ref': '#/components/schemas/ArticleCategory' - } - } - } - let(:id) { 'invalid' } + let(:id) { create(:article_category, name: 'dairy').id } run_test! end + it_handles_invalid_token_with_id(:article_category) + it_cannot_find_object end end end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 176e9e21..b0831ed9 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -30,7 +30,7 @@ module ApiHelper end end - def self.it_handles_invalid_scope(description="missing scope") + def self.it_handles_invalid_scope(description = "missing scope") context 'with invalid scope' do let(:api_scopes) { ['none'] } @@ -45,6 +45,7 @@ module ApiHelper context 'with invalid scope' do let(:api_scopes) { ['none'] } let(:id) { create(class_sym).id } + response 403, description do schema '$ref' => '#/components/schemas/Error403' run_test! @@ -52,18 +53,12 @@ module ApiHelper end end - def self.it_cannot_find_object(description="not found") - # 404 - response '404', description do - schema type: :object, properties: { - group_order_article: { - type: :object, - items: { - '$ref': '#/components/schemas/GroupOrderArticle' - } - } - } - let(:id) { 'invalid' } + def self.it_cannot_find_object(description = "not found") + let(:id) { 'invalid' } + + + response 404, description do + schema '$ref' => '#/components/schemas/Error404' run_test! end end diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml deleted file mode 100644 index 5fe3a5a3..00000000 --- a/swagger/v1/swagger.yaml +++ /dev/null @@ -1,169 +0,0 @@ ---- -openapi: 3.0.1 -info: - title: API V1 - version: v1 -paths: - "/user": - get: - summary: info about the currently logged-in user - tags: - - User - responses: - '200': - description: success - content: - application/json: - schema: - type: object - properties: - user: - type: object - properties: - id: - type: integer - name: - type: string - description: full name - email: - type: string - description: email address - locale: - type: string - description: language code - required: - - id - - name - - email - '401': - description: not logged-in - content: - application/json: - schema: - "$ref": "#/components/schemas/Error401" - '403': - description: missing scope - content: - application/json: - schema: - "$ref": "#/components/schemas/Error403" - "/user/financial_overview": - get: - summary: financial summary about the currently logged-in user - tags: - - User - - FinancialTransaction - responses: - '200': - description: success - content: - application/json: - schema: - type: object - properties: - account_balance: - type: number - description: booked accout balance of ordergroup - available_funds: - type: number - description: fund available to order articles - financial_transaction_class_sums: - type: object - properties: - id: - type: integer - description: id of the financial transaction class - name: - type: string - description: name of the financial transaction class - amount: - type: number - description: sum of the amounts belonging to the financial - transaction class - required: - - id - - name - - amount - required: - - account_balance - - available_funds - - financial_transaction_class_sums - '401': - description: not logged-in - content: - application/json: - schema: - "$ref": "#/components/schemas/Error401" - '403': - description: missing scope - content: - application/json: - schema: - "$ref": "#/components/schemas/Error403" -components: - schemas: - Error: - type: object - properties: - error: - type: string - description: error code - error_description: - type: string - description: human-readable error message (localized) - Error401: - type: object - properties: - error: - type: string - description: "unauthorized" - error_description: - "$ref": "#/components/schemas/Error/properties/error_description" - Error403: - type: object - properties: - error: - type: string - description: "forbidden or invalid_scope" - error_description: - "$ref": "#/components/schemas/Error/properties/error_description" - Error404: - type: object - properties: - error: - type: string - description: "not_found" - error_description: - "$ref": "#/components/schemas/Error/properties/error_description" - Error422: - type: object - properties: - error: - type: string - description: unprocessable entity - error_description: - "$ref": "#/components/schemas/Error/properties/error_description" - securitySchemes: - oauth2: - type: oauth2 - flows: - implicit: - authorizationUrl: http://localhost:3000/f/oauth/authorize - scopes: - config:user: reading Foodsoft configuration for regular users - config:read: reading Foodsoft configuration values - config:write: reading and updating Foodsoft configuration values - finance:user: accessing your own financial transactions - finance:read: reading all financial transactions - finance:write: reading and creating financial transactions - user:read: reading your own user profile - user:write: reading and updating your own user profile - offline_access: retain access after user has logged out -servers: -- url: http://{defaultHost}/f/api/v1 - variables: - defaultHost: - default: localhost:3000 -security: -- oauth2: - - user:read -- 2.45.2 From fc9637f39878afd47ec7e6e190c1ccdca7157607 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 11:58:02 +0100 Subject: [PATCH 24/46] refactor: financial transaction classes --- .../api/financial_transaction_classes_spec.rb | 37 +++---------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/spec/requests/api/financial_transaction_classes_spec.rb b/spec/requests/api/financial_transaction_classes_spec.rb index b016b8dd..8b62a721 100644 --- a/spec/requests/api/financial_transaction_classes_spec.rb +++ b/spec/requests/api/financial_transaction_classes_spec.rb @@ -7,16 +7,15 @@ describe 'Financial Transaction Classes', type: :request do get 'financial transaction classes' do tags 'Category' produces 'application/json' - parameter name: "per_page", in: :query, type: :integer, required: false parameter name: "page", in: :query, type: :integer, required: false - let(:page) { 1 } - let(:per_page) { 10 } - let(:financial_transaction_class) { create(:financial_transaction_class) } response '200', 'success' do schema type: :object, properties: { + meta: { + '$ref' => '#/components/schemas/Meta' + }, financial_transaction_class: { type: :array, items: { @@ -47,36 +46,12 @@ describe 'Financial Transaction Classes', type: :request do } } } - let(:id) { FinancialTransactionClass.create(name: 'TestTransaction').id } + let(:id) { create(:financial_transaction_class).id } run_test! end - response '401', 'not logged in' do - schema type: :object, properties: { - financial_transaction_classes: { - type: :array, - items: { - '$ref': '#/components/schemas/FinancialTransactionClass' - } - } - } - let(:Authorization) { 'abc' } - let(:id) { FinancialTransactionClass.create(name: 'TestTransaction').id } - run_test! - end - - response '404', 'financial transaction class not found' do - schema type: :object, properties: { - financial_transaction_classes: { - type: :array, - items: { - '$ref': '#/components/schemas/FinancialTransactionClass' - } - } - } - let(:id) { 'invalid' } - run_test! - end + it_handles_invalid_token_with_id :financial_transaction + it_cannot_find_object 'financial transaction class not found' end end end -- 2.45.2 From 3222e79a345590c4ef8772a202e6a094a2c5930a Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 12:18:04 +0100 Subject: [PATCH 25/46] refactor: nullable values, financial transaction types --- .../api/financial_transaction_types_spec.rb | 35 +++--------- spec/swagger_helper.rb | 53 ++++++++++++++++--- 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/spec/requests/api/financial_transaction_types_spec.rb b/spec/requests/api/financial_transaction_types_spec.rb index 68eda4da..2e737f7e 100644 --- a/spec/requests/api/financial_transaction_types_spec.rb +++ b/spec/requests/api/financial_transaction_types_spec.rb @@ -9,11 +9,12 @@ describe 'Financial Transaction types', type: :request do produces 'application/json' parameter name: "per_page", in: :query, type: :integer, required: false parameter name: "page", in: :query, type: :integer, required: false - let(:page) { 1 } - let(:per_page) { 10 } let(:financial_transaction_type) { create(:financial_transaction_type) } response '200', 'success' do schema type: :object, properties: { + meta: { + '$ref' => '#/components/schemas/Meta' + }, financial_transaction_type: { type: :array, items: { @@ -43,36 +44,12 @@ describe 'Financial Transaction types', type: :request do } } } - let(:id) { FinancialTransactionType.create(name: 'TestType').id } + let(:id) { create(:financial_transaction_type).id } run_test! end - response '401', 'not logged in' do - schema type: :object, properties: { - financial_transaction_types: { - type: :array, - items: { - '$ref': '#/components/schemas/FinancialTransactionType' - } - } - } - let(:Authorization) { 'abc' } - let(:id) { FinancialTransactionType.create(name: 'TestType').id } - run_test! - end - - response '404', 'financial transaction type not found' do - schema type: :object, properties: { - financial_transaction_types: { - type: :array, - items: { - '$ref': '#/components/schemas/FinancialTransactionType' - } - } - } - let(:id) { 'invalid' } - run_test! - end + it_handles_invalid_token_with_id :financial_transaction_type + it_cannot_find_object 'financial transaction type not found' end end end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 0eeb05ac..d0f5bfc2 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -50,17 +50,20 @@ RSpec.configure do |config| description: 'when the order was opened' }, ends: { - type: ['string', 'null'], + type: :string, + nullable: true, format: 'date-time', description: 'when the order will close or was closed' }, boxfill: { - type: ['string', 'null'], + type: :string, + nullable: true, format: 'date-time', description: 'when the order will enter or entered the boxfill phase' }, pickup: { - type: ['string', 'null'], + type: :string, + nullable: true, format: :date, description: 'pickup date' }, @@ -88,7 +91,8 @@ RSpec.configure do |config| description: 'id of supplier, or 0 for stock articles' }, supplier_name: { - type: %w[string null], + type: :string, + nullable: true, description: 'name of the supplier, or null for stock articles' }, unit: { @@ -100,15 +104,18 @@ RSpec.configure do |config| description: 'units can only be ordered from the supplier in multiples of unit_quantity' }, note: { - type: %w[string null], + type: :string, + nullable: true, description: 'generic note' }, manufacturer: { - type: %w[string null], + type: :string, + nullable: true, description: 'manufacturer' }, origin: { - type: %w[string null], + type: :string, + nullable: true, description: 'origin, preferably (starting with a) 2-letter ISO country code' }, article_category_id: { @@ -187,10 +194,12 @@ RSpec.configure do |config| }, user_id: { type: :integer, + nullable: true, description: 'id of user who entered the transaction (may be null for deleted users or 0 for a system user)' }, user_name: { type: :string, + nullable: true, description: 'name of user who entered the transaction (may be null or empty string for deleted users or system users)' }, financial_transaction_type_name: { @@ -244,9 +253,37 @@ RSpec.configure do |config| }, name: { type: :string + }, + name_short: { + type: :string, + nullable: true, + description: 'short name (used for bank transfers)' + }, + bank_account_id: { + type: :integer, + nullable: true, + description: 'id of the bank account used for this transaction type' + }, + bank_account_name: { + type: :string, + nullable: true, + description: 'name of the bank account used for this transaction type' + }, + bank_account_iban: { + type: :string, + nullable: true, + description: 'IBAN of the bank account used for this transaction type' + }, + financial_transaction_class_id: { + type: :integer, + description: 'id of the class of the transaction' + }, + financial_transaction_class_name: { + type: :string, + description: 'name of the class of the transaction' } }, - required: %w[id name financial_transaction_class] + required: %w[id name financial_transaction_class_id financial_transaction_class_name] }, GroupOrderArticleForUpdate: { type: :object, -- 2.45.2 From 6bacbe9584cea8939318ac684a4421a40f3cf016 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 12:21:57 +0100 Subject: [PATCH 26/46] fix: config --- spec/requests/api/configs_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/requests/api/configs_spec.rb b/spec/requests/api/configs_spec.rb index 6a389148..75f48ceb 100644 --- a/spec/requests/api/configs_spec.rb +++ b/spec/requests/api/configs_spec.rb @@ -10,6 +10,7 @@ describe 'Config', type: :request do let(:api_scopes) { ['config:user'] } response '200', 'success' do + schema type: :object, properties: {} run_test! end -- 2.45.2 From 1c5a3c686456ff52a8cc6fcf8b10bdfb5de4d149 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 12:28:06 +0100 Subject: [PATCH 27/46] fix: financial category tag --- spec/requests/api/financial_transactions_spec.rb | 8 ++------ spec/requests/api/user/financial_transactions_spec.rb | 4 ++-- spec/requests/api/user/users_spec.rb | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/spec/requests/api/financial_transactions_spec.rb b/spec/requests/api/financial_transactions_spec.rb index ce396a6e..d5c028a3 100644 --- a/spec/requests/api/financial_transactions_spec.rb +++ b/spec/requests/api/financial_transactions_spec.rb @@ -17,11 +17,7 @@ describe 'Financial Transaction', type: :request do response '200', 'success' do schema type: :object, properties: { meta: { - type: :object, - items: - { - '$ref': '#/components/schemas/Meta' - } + '$ref' => '#/components/schemas/Meta' }, financial_transaction: { type: :array, @@ -40,7 +36,7 @@ describe 'Financial Transaction', type: :request do path '/financial_transactions/{id}' do get 'Retrieves a financial transaction ' do - tags 'Category' + tags 'Financial Transaction' produces 'application/json' parameter name: :id, in: :path, type: :string diff --git a/spec/requests/api/user/financial_transactions_spec.rb b/spec/requests/api/user/financial_transactions_spec.rb index f3ceebb6..ad1cdbdf 100644 --- a/spec/requests/api/user/financial_transactions_spec.rb +++ b/spec/requests/api/user/financial_transactions_spec.rb @@ -14,7 +14,7 @@ describe 'User', type: :request do path '/user/financial_transactions' do post 'create new financial transaction (requires enabled self service)' do - tags 'User', 'FinancialTransaction' + tags "Financial Transaction" consumes 'application/json' produces 'application/json' parameter name: "per_page", in: :query, type: :integer, required: false @@ -105,7 +105,7 @@ describe 'User', type: :request do path '/user/financial_transactions/{id}' do get 'find financial transaction by id' do - tags 'User', 'FinancialTransaction' + tags 'User', 'Financial Transaction' produces 'application/json' parameter name: :id, in: :path, type: :string diff --git a/spec/requests/api/user/users_spec.rb b/spec/requests/api/user/users_spec.rb index 568c6fb7..01031180 100644 --- a/spec/requests/api/user/users_spec.rb +++ b/spec/requests/api/user/users_spec.rb @@ -50,7 +50,7 @@ describe 'User', type: :request do path '/user/financial_overview' do get 'financial summary about the currently logged-in user' do - tags 'User', 'FinancialTransaction' + tags 'User', 'Financial Transaction' produces 'application/json' let(:user) { create :user, :ordergroup } FinancialTransactionClass.create(name: 'TestTransaction') -- 2.45.2 From a32bc8829824a51fadd343a69b52999ca56b0671 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 12:59:06 +0100 Subject: [PATCH 28/46] refactor: financial transaction spec --- .../api/financial_transactions_spec.rb | 24 ++++--------------- spec/support/api_helper.rb | 6 ++--- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/spec/requests/api/financial_transactions_spec.rb b/spec/requests/api/financial_transactions_spec.rb index d5c028a3..b3f3a85d 100644 --- a/spec/requests/api/financial_transactions_spec.rb +++ b/spec/requests/api/financial_transactions_spec.rb @@ -26,11 +26,10 @@ describe 'Financial Transaction', type: :request do } } } - let(:page) { 1 } - let(:per_page) { 10 } + run_test! end - it_handles_invalid_scope + it_handles_invalid_token_and_scope end end @@ -52,22 +51,9 @@ describe 'Financial Transaction', type: :request do let(:id) { FinancialTransaction.create(user: user).id } run_test! end - it_handles_invalid_scope_with_id(:financial_transaction, 'missing scope or no permission') - - response '404', 'financial transaction not found' do - schema type: :object, properties: { - financial_transaction: { - type: :array, - items: { - '$ref': '#/components/schemas/FinancialTransaction' - } - } - } - let(:id) { 'invalid' } - run_test! - end - # response 403 - it_handles_invalid_scope_with_id(:financial_transaction, 'missing scope or no permission') + it_handles_invalid_token_with_id :financial_transaction + it_handles_invalid_scope_with_id :financial_transaction + it_cannot_find_object 'financial transaction not found' end end end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index b0831ed9..0c8c83d5 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -30,7 +30,7 @@ module ApiHelper end end - def self.it_handles_invalid_scope(description = "missing scope") + def self.it_handles_invalid_scope(description = 'missing scope') context 'with invalid scope' do let(:api_scopes) { ['none'] } @@ -41,7 +41,7 @@ module ApiHelper end end - def self.it_handles_invalid_scope_with_id(class_sym, description) + def self.it_handles_invalid_scope_with_id(class_sym, description = 'missing scope') context 'with invalid scope' do let(:api_scopes) { ['none'] } let(:id) { create(class_sym).id } @@ -53,7 +53,7 @@ module ApiHelper end end - def self.it_cannot_find_object(description = "not found") + def self.it_cannot_find_object(description = 'not found') let(:id) { 'invalid' } -- 2.45.2 From e41c6e5c2098860cbba8852f0b1982ea3af6ad4a Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 13:30:32 +0100 Subject: [PATCH 29/46] refactor: financial transaction spec --- .../api/user/financial_transactions_spec.rb | 79 ++++++------------- spec/swagger_helper.rb | 79 ++++++++++--------- 2 files changed, 65 insertions(+), 93 deletions(-) diff --git a/spec/requests/api/user/financial_transactions_spec.rb b/spec/requests/api/user/financial_transactions_spec.rb index ad1cdbdf..a0dad6ff 100644 --- a/spec/requests/api/user/financial_transactions_spec.rb +++ b/spec/requests/api/user/financial_transactions_spec.rb @@ -17,10 +17,7 @@ describe 'User', type: :request do tags "Financial Transaction" consumes 'application/json' produces 'application/json' - parameter name: "per_page", in: :query, type: :integer, required: false - parameter name: "page", in: :query, type: :integer, required: false - let(:page) { 1 } - let(:per_page) { 20 } + parameter name: :financial_transaction, in: :body, schema: { type: :object, properties: { @@ -29,62 +26,46 @@ describe 'User', type: :request do note: { type: :string } } } + let(:financial_transaction) { { amount: 3, financial_transaction_type_id: create(:financial_transaction_type).id, note: 'lirum larum' } } response '200', 'success' do schema type: :object, properties: { - financial_transaction_for_create: { - type: :object, - items: { - '$ref': '#/components/schemas/FinancialTransactionForCreate' - } - } + financial_transaction: { '$ref': '#/components/schemas/FinancialTransaction' } } run_test! end - # 401 - it_handles_invalid_token_with_id(:financial_transaction) - - # 403 - # description: user has no ordergroup, is below minimum balance, self service is disabled, or missing scope + it_handles_invalid_token_with_id :financial_transaction it_handles_invalid_scope_with_id(:financial_transaction, 'user has no ordergroup, is below minimum balance, self service is disabled, or missing scope') - # TODO: fix 404 and 422 - # 404 - # Type not found - # description: financial transaction type not found - # Should be 404, but is 200 with validation errors.. - # Rswag::Specs::UnexpectedResponse: - # Expected response code '404' to match '200' - # Response body: {"error":"not_found","error_description":"Couldn't find FinancialTransactionType with 'id'=invalid"} - # let(:financial_transaction) { { amount: 3, financial_transaction_type_id: 'invalid', note: 'lirum larum' } } - # response '404', 'invalid parameter value' do - # schema '$ref' => '#/components/schemas/Error404' - # run_test! - # end + response '404', 'financial transaction type not found' do + schema '$ref' => '#/components/schemas/Error404' + let(:financial_transaction) { { amount: 3, financial_transaction_type_id: 'invalid', note: 'lirum larum' } } + run_test! + end - # 422 + # TODO: fix controller to actually send a 422 for invalid params? + # Expected response code '200' to match '422' + # Response body: {"financial_transaction":{"id":316,"user_id":599,"user_name":"Lisbeth ","amount":-3.0,"note":"-2","created_at":"2022-12-12T13:05:32.000+01:00","financial_transaction_type_id":346,"financial_transaction_type_name":"aut est iste #9"}} + # # response '422', 'invalid parameter value' do + # # schema '$ref' => '#/components/schemas/Error422' # let(:financial_transaction) { { amount: -3, financial_transaction_type_id: create(:financial_transaction_type).id, note: -2 } } - - # schema '$ref' => '#/components/schemas/Error422' # run_test! # end end + get "financial transactions of the member's ordergroup" do tags 'User', 'Financial Transaction' produces 'application/json' + parameter name: "per_page", in: :query, type: :integer, required: false + parameter name: "page", in: :query, type: :integer, required: false + response '200', 'success' do schema type: :object, properties: { - meta: { - type: :object, - items: - { - '$ref': '#/components/schemas/Meta' - } - }, + meta: { '$ref': '#/components/schemas/Meta' }, financial_transaction: { type: :array, items: { @@ -98,7 +79,7 @@ describe 'User', type: :request do expect(data['financial_transactions'].first['id']).to eq(ft.id) end end - # responses 401 & 403 + it_handles_invalid_token_and_scope end end @@ -125,23 +106,9 @@ describe 'User', type: :request do end end - # 401 - it_handles_invalid_token_with_id(:financial_transaction) - # 403 - it_handles_invalid_scope_with_id(:financial_transaction, 'user has no ordergroup or missing scope') - # 404 - response '404', 'financial transaction not found' do - schema type: :object, properties: { - financial_transaction: { - type: :object, - items: { - '$ref': '#/components/schemas/FinancialTransaction' - } - } - } - let(:id) { 'invalid' } - run_test! - end + it_handles_invalid_token_with_id :financial_transaction + it_handles_invalid_scope_with_id :financial_transaction, 'user has no ordergroup or missing scope' + it_cannot_find_object 'financial transaction not found' end end end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index d0f5bfc2..dd06f2cc 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -174,45 +174,50 @@ RSpec.configure do |config| required: %w[id name] }, FinancialTransaction: { - type: :object, - properties: { - id: { - type: :integer - }, - amount: { - type: :integer, - description: 'amount credited (negative for a debit transaction)' - }, - financial_transaction_type_id: + allOf: [ + { '$ref': '#/components/schemas/FinancialTransactionForCreate' }, { - type: :integer, - description: 'id of the type of the transaction' - }, - note: { - type: :string, - description: 'note entered with the transaction' - }, - user_id: { - type: :integer, - nullable: true, - description: 'id of user who entered the transaction (may be null for deleted users or 0 for a system user)' - }, - user_name: { - type: :string, - nullable: true, - description: 'name of user who entered the transaction (may be null or empty string for deleted users or system users)' - }, - financial_transaction_type_name: { - type: :string, - description: 'name of the type of the transaction' - }, - created_at: { - type: :string, - format: :datetime, - description: 'when the transaction was entered' + type: :object, + properties: { + id: { + type: :integer + }, + amount: { + type: :integer, + description: 'amount credited (negative for a debit transaction)' + }, + financial_transaction_type_id: + { + type: :integer, + description: 'id of the type of the transaction' + }, + note: { + type: :string, + description: 'note entered with the transaction' + }, + user_id: { + type: :integer, + nullable: true, + description: 'id of user who entered the transaction (may be null for deleted users or 0 for a system user)' + }, + user_name: { + type: :string, + nullable: true, + description: 'name of user who entered the transaction (may be null or empty string for deleted users or system users)' + }, + financial_transaction_type_name: { + type: :string, + description: 'name of the type of the transaction' + }, + created_at: { + type: :string, + format: 'date-time', + description: 'when the transaction was entered' + } + }, + required: %w[id user_id user_name financial_transaction_type_name created_at] } - }, - required: %w[amount note user_id] + ] }, FinancialTransactionForCreate: { type: :object, -- 2.45.2 From 57593db96def6f4c18e866fc4c6cff5bfbbc8c14 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 15:15:35 +0100 Subject: [PATCH 30/46] refactor: order articles spec --- spec/requests/api/order_articles_spec.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/requests/api/order_articles_spec.rb b/spec/requests/api/order_articles_spec.rb index 304869e3..50774110 100644 --- a/spec/requests/api/order_articles_spec.rb +++ b/spec/requests/api/order_articles_spec.rb @@ -9,15 +9,15 @@ describe 'Order Articles', type: :request do produces 'application/json' parameter name: "per_page", in: :query, type: :integer, required: false parameter name: "page", in: :query, type: :integer, required: false - let(:page) { 1 } - let(:per_page) { 10 } parameter name: 'q', in: :query, required: false, description: "'member' show articles ordered by the user's ordergroup, 'all' by all members, and 'supplier' ordered at the supplier", schema: { type: :object, - ordered: { - type: :string, - enum: %w[member all supplier] + properties: { + ordered: { + type: :string, + enum: %w[member all supplier] + } } } let(:api_scopes) { ['orders:read', 'orders:write'] } @@ -106,10 +106,7 @@ describe 'Order Articles', type: :request do tags 'Order' produces 'application/json' parameter name: 'id', in: :path, type: :integer, minimum: 1, required: true - let(:api_scopes) { ['orders:read', 'orders:write'] } - let(:order) { create(:order, article_count: 1) } - let(:id) { order.order_articles.first.id } response '200', 'success' do schema type: :object, properties: { @@ -117,11 +114,14 @@ describe 'Order Articles', type: :request do '$ref': '#/components/schemas/OrderArticle' } } + let(:order) { create(:order, article_count: 1) } + let(:id) { order.order_articles.first.id } run_test! end it_handles_invalid_token_and_scope + it_cannot_find_object 'order article not found' end end end -- 2.45.2 From 4c0a7ae938171c27e1913b55f26167ef1dbe1003 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 15:54:53 +0100 Subject: [PATCH 31/46] refactor: extract id parameter --- spec/requests/api/article_categories_spec.rb | 2 +- .../api/financial_transaction_classes_spec.rb | 2 +- spec/requests/api/financial_transaction_types_spec.rb | 2 +- spec/requests/api/financial_transactions_spec.rb | 2 +- spec/requests/api/order_articles_spec.rb | 2 +- spec/requests/api/orders_spec.rb | 3 ++- spec/requests/api/user/financial_transactions_spec.rb | 2 +- spec/requests/api/user/group_order_articles_spec.rb | 11 +++++------ spec/support/api_helper.rb | 4 ++++ 9 files changed, 17 insertions(+), 13 deletions(-) diff --git a/spec/requests/api/article_categories_spec.rb b/spec/requests/api/article_categories_spec.rb index 68467241..937f2690 100644 --- a/spec/requests/api/article_categories_spec.rb +++ b/spec/requests/api/article_categories_spec.rb @@ -33,7 +33,7 @@ describe 'Article Categories', type: :request do get 'find article category by id' do tags 'Category' produces 'application/json' - parameter name: :id, in: :path, type: :string + id_url_param response '200', 'article category found' do schema type: :object, properties: { diff --git a/spec/requests/api/financial_transaction_classes_spec.rb b/spec/requests/api/financial_transaction_classes_spec.rb index 8b62a721..9e0bd1a6 100644 --- a/spec/requests/api/financial_transaction_classes_spec.rb +++ b/spec/requests/api/financial_transaction_classes_spec.rb @@ -35,7 +35,7 @@ describe 'Financial Transaction Classes', type: :request do get 'Retrieves a financial transaction class' do tags 'Category' produces 'application/json' - parameter name: :id, in: :path, type: :string + id_url_param response '200', 'financial transaction class found' do schema type: :object, properties: { diff --git a/spec/requests/api/financial_transaction_types_spec.rb b/spec/requests/api/financial_transaction_types_spec.rb index 2e737f7e..94caacf4 100644 --- a/spec/requests/api/financial_transaction_types_spec.rb +++ b/spec/requests/api/financial_transaction_types_spec.rb @@ -33,7 +33,7 @@ describe 'Financial Transaction types', type: :request do get 'find financial transaction type by id' do tags 'Category' produces 'application/json' - parameter name: :id, in: :path, type: :string + id_url_param response '200', 'financial transaction type found' do schema type: :object, properties: { diff --git a/spec/requests/api/financial_transactions_spec.rb b/spec/requests/api/financial_transactions_spec.rb index b3f3a85d..aa9afaeb 100644 --- a/spec/requests/api/financial_transactions_spec.rb +++ b/spec/requests/api/financial_transactions_spec.rb @@ -37,7 +37,7 @@ describe 'Financial Transaction', type: :request do get 'Retrieves a financial transaction ' do tags 'Financial Transaction' produces 'application/json' - parameter name: :id, in: :path, type: :string + id_url_param response '200', 'financial transaction found' do schema type: :object, properties: { diff --git a/spec/requests/api/order_articles_spec.rb b/spec/requests/api/order_articles_spec.rb index 50774110..88c68b0a 100644 --- a/spec/requests/api/order_articles_spec.rb +++ b/spec/requests/api/order_articles_spec.rb @@ -105,7 +105,7 @@ describe 'Order Articles', type: :request do get 'order articles' do tags 'Order' produces 'application/json' - parameter name: 'id', in: :path, type: :integer, minimum: 1, required: true + id_url_param let(:api_scopes) { ['orders:read', 'orders:write'] } response '200', 'success' do diff --git a/spec/requests/api/orders_spec.rb b/spec/requests/api/orders_spec.rb index 43f546a3..05eea3e2 100644 --- a/spec/requests/api/orders_spec.rb +++ b/spec/requests/api/orders_spec.rb @@ -39,7 +39,8 @@ describe 'Orders', type: :request do get 'Order' do tags 'Order' produces 'application/json' - parameter name: 'id', in: :path, type: :integer, minimum: 1, required: true + id_url_param + let(:order) { create(:order) } let(:id) { order.id } diff --git a/spec/requests/api/user/financial_transactions_spec.rb b/spec/requests/api/user/financial_transactions_spec.rb index a0dad6ff..1eca1895 100644 --- a/spec/requests/api/user/financial_transactions_spec.rb +++ b/spec/requests/api/user/financial_transactions_spec.rb @@ -88,7 +88,7 @@ describe 'User', type: :request do get 'find financial transaction by id' do tags 'User', 'Financial Transaction' produces 'application/json' - parameter name: :id, in: :path, type: :string + id_url_param response '200', 'success' do schema type: :object, properties: { diff --git a/spec/requests/api/user/group_order_articles_spec.rb b/spec/requests/api/user/group_order_articles_spec.rb index 55e44dd1..e451fb10 100644 --- a/spec/requests/api/user/group_order_articles_spec.rb +++ b/spec/requests/api/user/group_order_articles_spec.rb @@ -107,9 +107,8 @@ describe 'User', type: :request do get 'find group order article by id' do tags 'User', 'GroupOrderArticle' produces 'application/json' - parameter name: :id, in: :path, type: :string + id_url_param - let(:id) { goa.id } response '200', 'success' do schema type: :object, properties: { group_order_article: { @@ -119,6 +118,7 @@ describe 'User', type: :request do } } } + let(:id) { goa.id } run_test! do |response| data = JSON.parse(response.body) expect(data['group_order_article']['id']).to eq(goa.id) @@ -155,7 +155,7 @@ describe 'User', type: :request do tags 'User', 'GroupOrderArticle' consumes 'application/json' produces 'application/json' - parameter name: :id, in: :path, type: :string + id_url_param parameter name: :group_order_article, in: :body, schema: { type: :object, @@ -219,11 +219,9 @@ describe 'User', type: :request do tags 'User', 'Order' consumes 'application/json' produces 'application/json' + id_url_param let(:api_scopes) { ['group_orders:user'] } - parameter name: :id, in: :path, type: :string - - let(:id) { goa.id } response '200', 'success' do schema type: :object, properties: { group_order_article: { @@ -233,6 +231,7 @@ describe 'User', type: :request do } } } + let(:id) { goa.id } run_test! end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 0c8c83d5..233f6584 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -67,5 +67,9 @@ module ApiHelper it_handles_invalid_token(*args) it_handles_invalid_scope(*args) end + + def self.id_url_param + parameter name: :id, in: :path, type: :integer, required: true + end end end -- 2.45.2 From edd6e2451d69e1ec16a53f685adefbf061ceea6a Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 16:00:49 +0100 Subject: [PATCH 32/46] refactor: id in helper functions actually not needed --- spec/requests/api/article_categories_spec.rb | 2 +- .../api/financial_transaction_classes_spec.rb | 2 +- .../api/financial_transaction_types_spec.rb | 2 +- .../api/financial_transactions_spec.rb | 4 +- spec/requests/api/orders_spec.rb | 5 +- .../api/user/financial_transactions_spec.rb | 8 ++-- .../api/user/group_order_articles_spec.rb | 47 ++++--------------- spec/support/api_helper.rb | 9 ++-- 8 files changed, 25 insertions(+), 54 deletions(-) diff --git a/spec/requests/api/article_categories_spec.rb b/spec/requests/api/article_categories_spec.rb index 937f2690..c8b60984 100644 --- a/spec/requests/api/article_categories_spec.rb +++ b/spec/requests/api/article_categories_spec.rb @@ -47,7 +47,7 @@ describe 'Article Categories', type: :request do let(:id) { create(:article_category, name: 'dairy').id } run_test! end - it_handles_invalid_token_with_id(:article_category) + it_handles_invalid_token_with_id it_cannot_find_object end end diff --git a/spec/requests/api/financial_transaction_classes_spec.rb b/spec/requests/api/financial_transaction_classes_spec.rb index 9e0bd1a6..2e3b76c4 100644 --- a/spec/requests/api/financial_transaction_classes_spec.rb +++ b/spec/requests/api/financial_transaction_classes_spec.rb @@ -50,7 +50,7 @@ describe 'Financial Transaction Classes', type: :request do run_test! end - it_handles_invalid_token_with_id :financial_transaction + it_handles_invalid_token_with_id it_cannot_find_object 'financial transaction class not found' end end diff --git a/spec/requests/api/financial_transaction_types_spec.rb b/spec/requests/api/financial_transaction_types_spec.rb index 94caacf4..6ad8b07b 100644 --- a/spec/requests/api/financial_transaction_types_spec.rb +++ b/spec/requests/api/financial_transaction_types_spec.rb @@ -48,7 +48,7 @@ describe 'Financial Transaction types', type: :request do run_test! end - it_handles_invalid_token_with_id :financial_transaction_type + it_handles_invalid_token_with_id it_cannot_find_object 'financial transaction type not found' end end diff --git a/spec/requests/api/financial_transactions_spec.rb b/spec/requests/api/financial_transactions_spec.rb index aa9afaeb..e683ea0b 100644 --- a/spec/requests/api/financial_transactions_spec.rb +++ b/spec/requests/api/financial_transactions_spec.rb @@ -51,8 +51,8 @@ describe 'Financial Transaction', type: :request do let(:id) { FinancialTransaction.create(user: user).id } run_test! end - it_handles_invalid_token_with_id :financial_transaction - it_handles_invalid_scope_with_id :financial_transaction + it_handles_invalid_token_with_id + it_handles_invalid_scope_with_id it_cannot_find_object 'financial transaction not found' end end diff --git a/spec/requests/api/orders_spec.rb b/spec/requests/api/orders_spec.rb index 05eea3e2..500b1aa0 100644 --- a/spec/requests/api/orders_spec.rb +++ b/spec/requests/api/orders_spec.rb @@ -42,17 +42,20 @@ describe 'Orders', type: :request do id_url_param let(:order) { create(:order) } - let(:id) { order.id } response '200', 'success' do schema type: :object, properties: { '$ref': '#/components/schemas/Order' } + let(:id) { order.id } run_test! do |response| expect(JSON.parse(response.body)['order']['id']).to eq order.id end end + + it_handles_invalid_token_and_scope + it_cannot_find_object 'order not found' end end end diff --git a/spec/requests/api/user/financial_transactions_spec.rb b/spec/requests/api/user/financial_transactions_spec.rb index 1eca1895..d5ff820c 100644 --- a/spec/requests/api/user/financial_transactions_spec.rb +++ b/spec/requests/api/user/financial_transactions_spec.rb @@ -36,8 +36,8 @@ describe 'User', type: :request do run_test! end - it_handles_invalid_token_with_id :financial_transaction - it_handles_invalid_scope_with_id(:financial_transaction, 'user has no ordergroup, is below minimum balance, self service is disabled, or missing scope') + it_handles_invalid_token_with_id + it_handles_invalid_scope_with_id 'user has no ordergroup, is below minimum balance, self service is disabled, or missing scope' response '404', 'financial transaction type not found' do schema '$ref' => '#/components/schemas/Error404' @@ -106,8 +106,8 @@ describe 'User', type: :request do end end - it_handles_invalid_token_with_id :financial_transaction - it_handles_invalid_scope_with_id :financial_transaction, 'user has no ordergroup or missing scope' + it_handles_invalid_token_with_id + it_handles_invalid_scope_with_id 'user has no ordergroup or missing scope' it_cannot_find_object 'financial transaction not found' end end diff --git a/spec/requests/api/user/group_order_articles_spec.rb b/spec/requests/api/user/group_order_articles_spec.rb index e451fb10..7a6e5ecf 100644 --- a/spec/requests/api/user/group_order_articles_spec.rb +++ b/spec/requests/api/user/group_order_articles_spec.rb @@ -80,12 +80,8 @@ describe 'User', type: :request do run_test! end - # 401 - it_handles_invalid_token_with_id(:group_order_article) - - # 403 - # description: user has no ordergroup, is below minimum balance, self service is disabled, or missing scope - it_handles_invalid_scope_with_id(:group_order_article, 'user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope') + it_handles_invalid_token_with_id + it_handles_invalid_scope_with_id 'user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope' # 404 response '404', 'order article not found in open orders' do @@ -125,32 +121,11 @@ describe 'User', type: :request do end end - # 401 - response 401, 'not logged-in' do - let(:Authorization) { 'abc' } - schema '$ref' => '#/components/schemas/Error401' - run_test! - end - # 403 - response 403, 'user has no ordergroup or missing scope' do - let(:api_scopes) { ['none'] } - schema '$ref' => '#/components/schemas/Error403' - run_test! - end - # 404 - response '404', 'group order article not found' do - schema type: :object, properties: { - group_order_article: { - type: :object, - items: { - '$ref': '#/components/schemas/GroupOrderArticle' - } - } - } - let(:id) { 'invalid' } - run_test! - end + it_handles_invalid_scope_with_id + it_handles_invalid_token_with_id + it_cannot_find_object 'group order article not found' end + patch 'update a group order article (but delete if quantity and tolerance are zero)' do tags 'User', 'GroupOrderArticle' consumes 'application/json' @@ -235,12 +210,7 @@ describe 'User', type: :request do run_test! end - # 401 - response 401, 'not logged-in' do - let(:Authorization) { 'abc' } - schema '$ref' => '#/components/schemas/Error401' - run_test! - end + it_handles_invalid_token_with_id # 403 response 403, 'user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope' do @@ -249,8 +219,7 @@ describe 'User', type: :request do run_test! end - # 404 - it_cannot_find_object('order article not found in open orders') + it_cannot_find_object 'order article not found in open orders' end end end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 233f6584..0727356b 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -18,10 +18,10 @@ module ApiHelper end end - def self.it_handles_invalid_token_with_id(class_sym) + def self.it_handles_invalid_token_with_id context 'with invalid access token' do let(:Authorization) { 'abc' } - let(:id) { create(class_sym).id } + let(:id) { 42 } # id doesn't matter here response 401, 'not logged-in' do schema '$ref' => '#/components/schemas/Error401' @@ -41,10 +41,10 @@ module ApiHelper end end - def self.it_handles_invalid_scope_with_id(class_sym, description = 'missing scope') + def self.it_handles_invalid_scope_with_id(description = 'missing scope') context 'with invalid scope' do let(:api_scopes) { ['none'] } - let(:id) { create(class_sym).id } + let(:id) { 42 } # id doesn't matter here response 403, description do schema '$ref' => '#/components/schemas/Error403' @@ -56,7 +56,6 @@ module ApiHelper def self.it_cannot_find_object(description = 'not found') let(:id) { 'invalid' } - response 404, description do schema '$ref' => '#/components/schemas/Error404' run_test! -- 2.45.2 From 482752facaccbab9408f84feb64d9791c123db36 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 16:02:14 +0100 Subject: [PATCH 33/46] refactor: meta oneline --- spec/requests/api/financial_transaction_classes_spec.rb | 4 +--- spec/requests/api/financial_transaction_types_spec.rb | 4 +--- spec/requests/api/financial_transactions_spec.rb | 4 +--- spec/requests/api/order_articles_spec.rb | 4 +--- spec/requests/api/orders_spec.rb | 6 +----- spec/requests/api/user/group_order_articles_spec.rb | 8 +------- 6 files changed, 6 insertions(+), 24 deletions(-) diff --git a/spec/requests/api/financial_transaction_classes_spec.rb b/spec/requests/api/financial_transaction_classes_spec.rb index 2e3b76c4..5482c10b 100644 --- a/spec/requests/api/financial_transaction_classes_spec.rb +++ b/spec/requests/api/financial_transaction_classes_spec.rb @@ -13,9 +13,7 @@ describe 'Financial Transaction Classes', type: :request do response '200', 'success' do schema type: :object, properties: { - meta: { - '$ref' => '#/components/schemas/Meta' - }, + meta: { '$ref' => '#/components/schemas/Meta' }, financial_transaction_class: { type: :array, items: { diff --git a/spec/requests/api/financial_transaction_types_spec.rb b/spec/requests/api/financial_transaction_types_spec.rb index 6ad8b07b..bdf8a0e1 100644 --- a/spec/requests/api/financial_transaction_types_spec.rb +++ b/spec/requests/api/financial_transaction_types_spec.rb @@ -12,9 +12,7 @@ describe 'Financial Transaction types', type: :request do let(:financial_transaction_type) { create(:financial_transaction_type) } response '200', 'success' do schema type: :object, properties: { - meta: { - '$ref' => '#/components/schemas/Meta' - }, + meta: { '$ref' => '#/components/schemas/Meta' }, financial_transaction_type: { type: :array, items: { diff --git a/spec/requests/api/financial_transactions_spec.rb b/spec/requests/api/financial_transactions_spec.rb index e683ea0b..3a741714 100644 --- a/spec/requests/api/financial_transactions_spec.rb +++ b/spec/requests/api/financial_transactions_spec.rb @@ -16,9 +16,7 @@ describe 'Financial Transaction', type: :request do response '200', 'success' do schema type: :object, properties: { - meta: { - '$ref' => '#/components/schemas/Meta' - }, + meta: { '$ref' => '#/components/schemas/Meta' }, financial_transaction: { type: :array, items: { diff --git a/spec/requests/api/order_articles_spec.rb b/spec/requests/api/order_articles_spec.rb index 88c68b0a..a129c438 100644 --- a/spec/requests/api/order_articles_spec.rb +++ b/spec/requests/api/order_articles_spec.rb @@ -33,9 +33,7 @@ describe 'Order Articles', type: :request do response '200', 'success' do schema type: :object, properties: { - meta: { - '$ref' => '#/components/schemas/Meta' - }, + meta: { '$ref' => '#/components/schemas/Meta' }, order_articles: { type: :array, items: { diff --git a/spec/requests/api/orders_spec.rb b/spec/requests/api/orders_spec.rb index 500b1aa0..84db5826 100644 --- a/spec/requests/api/orders_spec.rb +++ b/spec/requests/api/orders_spec.rb @@ -10,16 +10,12 @@ describe 'Orders', type: :request do produces 'application/json' parameter name: "per_page", in: :query, type: :integer, required: false parameter name: "page", in: :query, type: :integer, required: false - let(:page) { 1 } - let(:per_page) { 20 } let(:order) { create(:order) } response '200', 'success' do schema type: :object, properties: { - meta: { - '$ref' => '#/components/schemas/Meta' - }, + meta: { '$ref' => '#/components/schemas/Meta' }, ordes: { type: :array, items: { diff --git a/spec/requests/api/user/group_order_articles_spec.rb b/spec/requests/api/user/group_order_articles_spec.rb index 7a6e5ecf..ec14417f 100644 --- a/spec/requests/api/user/group_order_articles_spec.rb +++ b/spec/requests/api/user/group_order_articles_spec.rb @@ -25,13 +25,7 @@ describe 'User', type: :request do let(:per_page) { 20 } response '200', 'success' do schema type: :object, properties: { - meta: { - type: :object, - items: - { - '$ref': '#/components/schemas/Meta' - } - }, + meta: { '$ref': '#/components/schemas/Meta' }, group_order_article: { type: :array, items: { -- 2.45.2 From 64e59085b23a44d165c68b2e3301c3be20986a5f Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 16:02:43 +0100 Subject: [PATCH 34/46] fix: financial transaction amount float not int --- spec/swagger_helper.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index dd06f2cc..d2811feb 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -183,14 +183,13 @@ RSpec.configure do |config| type: :integer }, amount: { - type: :integer, + type: :float, description: 'amount credited (negative for a debit transaction)' }, - financial_transaction_type_id: - { - type: :integer, - description: 'id of the type of the transaction' - }, + financial_transaction_type_id: { + type: :integer, + description: 'id of the type of the transaction' + }, note: { type: :string, description: 'note entered with the transaction' @@ -223,7 +222,7 @@ RSpec.configure do |config| type: :object, properties: { amount: { - type: :integer, + type: :float, description: 'amount credited (negative for a debit transaction)' }, financial_transaction_type_id: -- 2.45.2 From 31a419c68957f01e882afe38d8d04d6a076d949f Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 16:14:14 +0100 Subject: [PATCH 35/46] fix: order article response body --- spec/requests/api/orders_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/orders_spec.rb b/spec/requests/api/orders_spec.rb index 84db5826..10495e3f 100644 --- a/spec/requests/api/orders_spec.rb +++ b/spec/requests/api/orders_spec.rb @@ -41,7 +41,7 @@ describe 'Orders', type: :request do response '200', 'success' do schema type: :object, properties: { - '$ref': '#/components/schemas/Order' + order: { '$ref' => '#/components/schemas/Order' } } let(:id) { order.id } -- 2.45.2 From 3765042e2da66af0a3cf33eda6d881c03c5620ee Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 16:33:17 +0100 Subject: [PATCH 36/46] fix: GroupOrderArticle Schema --- spec/swagger_helper.rb | 68 +++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index d2811feb..df863208 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -183,7 +183,8 @@ RSpec.configure do |config| type: :integer }, amount: { - type: :float, + type: :number, + format: :float, description: 'amount credited (negative for a debit transaction)' }, financial_transaction_type_id: { @@ -222,7 +223,8 @@ RSpec.configure do |config| type: :object, properties: { amount: { - type: :float, + type: :number, + format: :float, description: 'amount credited (negative for a debit transaction)' }, financial_transaction_type_id: @@ -305,37 +307,49 @@ RSpec.configure do |config| } }, GroupOrderArticleForCreate: { - type: :object, - properties: { - order_article_id: + allOf: [ + { '$ref': '#/components/schemas/GroupOrderArticleForUpdate' }, { - type: :integer, - description: 'id of order article' + type: :object, + properties: { + order_article_id: + { + type: :integer, + description: 'id of order article' + } + } } - } + ] }, GroupOrderArticle: { - type: :object, - properties: { - id: { - type: :integer - }, - result: { - type: :float, - description: 'number of units the users ordergroup will receive or has received' - }, - total_price: + allOf: [ + { '$ref': '#/components/schemas/GroupOrderArticleForCreate' }, { - type: :float, - description: 'total price of this group order article' - }, - order_article_id: - { - type: :integer, - description: 'id of order article' + type: :object, + properties: { + id: { + type: :integer + }, + result: { + type: :number, + format: :float, + description: 'number of units the users ordergroup will receive or has received' + }, + total_price: + { + type: :number, + format: :float, + description: 'total price of this group order article' + }, + order_article_id: + { + type: :integer, + description: 'id of order article' + } + }, + required: %w[order_article_id] } - }, - required: %w[order_article_id] + ] }, Meta: { type: :object, -- 2.45.2 From eac550daa9c673e54e7904221d7b584857d764bd Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 16:59:01 +0100 Subject: [PATCH 37/46] refactor: group order articles --- .../api/user/group_order_articles_spec.rb | 64 ++++++++----------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/spec/requests/api/user/group_order_articles_spec.rb b/spec/requests/api/user/group_order_articles_spec.rb index ec14417f..57959535 100644 --- a/spec/requests/api/user/group_order_articles_spec.rb +++ b/spec/requests/api/user/group_order_articles_spec.rb @@ -21,8 +21,8 @@ describe 'User', type: :request do produces 'application/json' parameter name: "per_page", in: :query, type: :integer, required: false parameter name: "page", in: :query, type: :integer, required: false - let(:page) { 1 } - let(:per_page) { 20 } + q_ordered_url_param + response '200', 'success' do schema type: :object, properties: { meta: { '$ref': '#/components/schemas/Meta' }, @@ -40,35 +40,27 @@ describe 'User', type: :request do end end - # response 401 it_handles_invalid_token - - # response 403 - it_handles_invalid_scope('user has no ordergroup or missing scope') + it_handles_invalid_scope 'user has no ordergroup or missing scope' end + post 'create new group order article' do tags 'User', 'Order' consumes 'application/json' produces 'application/json' - parameter name: :group_order_article, in: :body, schema: { - type: :object, - description: 'group order article to create', - properties: { - order_article_id: { type: :integer }, - quantity: { type: :integer }, - tolerance: { type: :string } - }, - required: true - } + parameter name: :group_order_article, in: :body, + description: 'group order article to create', + required: true, + schema: { '$ref': '#/components/schemas/GroupOrderArticleForCreate' } let(:group_order_article) { { order_article_id: order_articles.last.id, quantity: 1, tolerance: 2 } } response '200', 'success' do schema type: :object, properties: { - group_order_article_for_create: { - type: :object, - items: { - '$ref': '#/components/schemas/GroupOrderArticleForCreate' - } + group_order_article: { + '$ref': '#/components/schemas/GroupOrderArticle' + }, + order_article: { + '$ref': '#/components/schemas/OrderArticle' } } run_test! @@ -77,7 +69,6 @@ describe 'User', type: :request do it_handles_invalid_token_with_id it_handles_invalid_scope_with_id 'user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope' - # 404 response '404', 'order article not found in open orders' do let(:group_order_article) { { order_article_id: 'invalid', quantity: 1, tolerance: 2 } } schema '$ref' => '#/components/schemas/Error404' @@ -95,19 +86,20 @@ describe 'User', type: :request do path '/user/group_order_articles/{id}' do get 'find group order article by id' do - tags 'User', 'GroupOrderArticle' + tags 'User', 'Order' produces 'application/json' id_url_param response '200', 'success' do schema type: :object, properties: { group_order_article: { - type: :object, - items: { - '$ref': '#/components/schemas/GroupOrderArticle' - } + '$ref': '#/components/schemas/GroupOrderArticle' + }, + order_article: { + '$ref': '#/components/schemas/OrderArticle' } } + let(:id) { goa.id } run_test! do |response| data = JSON.parse(response.body) @@ -121,21 +113,15 @@ describe 'User', type: :request do end patch 'update a group order article (but delete if quantity and tolerance are zero)' do - tags 'User', 'GroupOrderArticle' + tags 'User', 'Order' consumes 'application/json' produces 'application/json' id_url_param + parameter name: :group_order_article, in: :body, + description: 'group order article update', + required: true, + schema: { '$ref': '#/components/schemas/GroupOrderArticleForUpdate' } - parameter name: :group_order_article, in: :body, schema: { - type: :object, - description: 'group order article to create', - properties: { - order_article_id: { type: :integer }, - quantity: { type: :integer }, - tolerance: { type: :string } - }, - required: true - } let(:id) { goa.id } let(:group_order_article) { { order_article_id: goa.order_article_id, quantity: 2, tolerance: 2 } } @@ -144,7 +130,7 @@ describe 'User', type: :request do group_order_article_for_create: { type: :object, items: { - '$ref': '#/components/schemas/GroupOrderArticleForUpdate' + } } } -- 2.45.2 From 5201d1740ce0e78ea1d07a34e9a8b92913009002 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 12 Dec 2022 16:59:17 +0100 Subject: [PATCH 38/46] refactor: q ordered article parameter --- spec/requests/api/order_articles_spec.rb | 13 ++----------- spec/support/api_helper.rb | 6 ++++++ spec/swagger_helper.rb | 9 +++++++++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/spec/requests/api/order_articles_spec.rb b/spec/requests/api/order_articles_spec.rb index a129c438..2285fff6 100644 --- a/spec/requests/api/order_articles_spec.rb +++ b/spec/requests/api/order_articles_spec.rb @@ -9,17 +9,8 @@ describe 'Order Articles', type: :request do produces 'application/json' parameter name: "per_page", in: :query, type: :integer, required: false parameter name: "page", in: :query, type: :integer, required: false - parameter name: 'q', in: :query, required: false, - description: "'member' show articles ordered by the user's ordergroup, 'all' by all members, and 'supplier' ordered at the supplier", - schema: { - type: :object, - properties: { - ordered: { - type: :string, - enum: %w[member all supplier] - } - } - } + q_ordered_url_param + let(:api_scopes) { ['orders:read', 'orders:write'] } let(:order) { create(:order, article_count: 4) } let(:order_articles) { order.order_articles } diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 0727356b..98732a19 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -70,5 +70,11 @@ module ApiHelper def self.id_url_param parameter name: :id, in: :path, type: :integer, required: true end + + def self.q_ordered_url_param + parameter name: 'q', in: :query, required: false, + description: "'member' show articles ordered by the user's ordergroup, 'all' by all members, and 'supplier' ordered at the supplier", + schema: { '$ref' => '#/components/schemas/q_ordered' } + end end end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index df863208..912504b8 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -351,6 +351,15 @@ RSpec.configure do |config| } ] }, + q_ordered: { + type: :object, + properties: { + ordered: { + type: :string, + enum: %w[member all supplier] + } + } + }, Meta: { type: :object, properties: { -- 2.45.2 From e4d0222ae2aab10bbecd78909a58d70067ddb239 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Wed, 14 Dec 2022 16:43:05 +0100 Subject: [PATCH 39/46] refactor: cleanup group order articles --- .../api/user/group_order_articles_spec.rb | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/spec/requests/api/user/group_order_articles_spec.rb b/spec/requests/api/user/group_order_articles_spec.rb index 57959535..bad73084 100644 --- a/spec/requests/api/user/group_order_articles_spec.rb +++ b/spec/requests/api/user/group_order_articles_spec.rb @@ -75,7 +75,6 @@ describe 'User', type: :request do run_test! end - # 422 response '422', 'invalid parameter value or group order article already exists' do let(:group_order_article) { { order_article_id: goa.order_article_id, quantity: 1, tolerance: 2 } } schema '$ref' => '#/components/schemas/Error422' @@ -127,42 +126,35 @@ describe 'User', type: :request do response '200', 'success' do schema type: :object, properties: { - group_order_article_for_create: { - type: :object, - items: { - - } + group_order_article: { + '$ref': '#/components/schemas/GroupOrderArticle' } } run_test! end - # 401 + response 401, 'not logged-in' do - let(:Authorization) { 'abc' } schema '$ref' => '#/components/schemas/Error401' + let(:Authorization) { 'abc' } run_test! end - # 403 + response 403, 'user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope' do let(:api_scopes) { ['none'] } schema '$ref' => '#/components/schemas/Error403' run_test! end - # 404 + response '404', 'order article not found in open orders' do schema type: :object, properties: { group_order_article: { - type: :object, - items: { - '$ref': '#/components/schemas/GroupOrderArticle' - } + '$ref': '#/components/schemas/GroupOrderArticle' } } let(:id) { 'invalid' } run_test! end - # 422 response '422', 'invalid parameter value' do let(:group_order_article) { { order_article_id: 'invalid', quantity: -5, tolerance: 'invalid' } } schema '$ref' => '#/components/schemas/Error422' @@ -180,10 +172,7 @@ describe 'User', type: :request do response '200', 'success' do schema type: :object, properties: { group_order_article: { - type: :object, - items: { - '$ref': '#/components/schemas/GroupOrderArticle' - } + '$ref': '#/components/schemas/GroupOrderArticle' } } let(:id) { goa.id } @@ -192,7 +181,6 @@ describe 'User', type: :request do it_handles_invalid_token_with_id - # 403 response 403, 'user has no ordergroup, order not open, is below minimum balance, has not enough apple points, or missing scope' do let(:api_scopes) { ['none'] } schema '$ref' => '#/components/schemas/Error403' -- 2.45.2 From c6c5daa3142b7060c4d2516c386439227d8a9481 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 2 Jan 2023 11:49:16 +0100 Subject: [PATCH 40/46] fix: rubocop RSpec/EmptyExampleGroup this is fixed in newer rubocop-rspec versions. see: https://github.com/rubocop/rubocop-rspec/issues/1177 --- .rubocop_todo.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b7e21eab..54397ff3 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -451,6 +451,24 @@ RSpec/DescribedClass: - "spec/models/ordergroup_spec.rb" - "spec/models/user_spec.rb" +# Offense count: 15 +# This cop supports unsafe autocorrection (--autocorrect-all). +RSpec/EmptyExampleGroup: + Exclude: + - 'spec/requests/api/article_categories_spec.rb' + - 'spec/requests/api/configs_spec.rb' + - 'spec/requests/api/financial_transaction_classes_spec.rb' + - 'spec/requests/api/financial_transaction_types_spec.rb' + - 'spec/requests/api/financial_transactions_spec.rb' + - 'spec/requests/api/navigations_spec.rb' + - 'spec/requests/api/order_articles_spec.rb' + - 'spec/requests/api/orders_spec.rb' + - 'spec/requests/api/user/financial_transactions_spec.rb' + - 'spec/requests/api/user/group_order_articles_spec.rb' + - 'spec/requests/api/user/users_spec.rb' + + + # Offense count: 65 # Configuration parameters: CountAsOne. RSpec/ExampleLength: -- 2.45.2 From a4a34167352ec765a8acd72ed02d567ad5370ca0 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 2 Jan 2023 11:51:00 +0100 Subject: [PATCH 41/46] fix: rubocop RSpec/VariableName snake_case for Authorization header --- .rubocop_todo.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 54397ff3..a0f30e21 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -599,6 +599,14 @@ RSpec/ScatteredSetup: - "spec/integration/balancing_spec.rb" - "spec/integration/login_spec.rb" +# Offense count: 4 +# Configuration parameters: AllowedPatterns, IgnoredPatterns. +# SupportedStyles: snake_case, camelCase +RSpec/VariableName: + EnforcedStyle: snake_case + AllowedPatterns: + - ^Authorization$ + # Offense count: 1 # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. RSpec/VerifiedDoubles: -- 2.45.2 From f8c9aaf35a466501272a429f903d0ce742e8c1da Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 2 Jan 2023 11:56:07 +0100 Subject: [PATCH 42/46] fix: rubocop Metrics/BlockLength for config/routes --- .rubocop_todo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index a0f30e21..1d3cd010 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -266,7 +266,7 @@ Metrics/AbcSize: # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, AllowedMethods, AllowedPatterns, IgnoredMethods, inherit_mode. # AllowedMethods: refine Metrics/BlockLength: - Max: 210 + Max: 212 # Offense count: 6 # Configuration parameters: CountBlocks. -- 2.45.2 From 18358484bab86c87c481419db390c22f71c18232 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 2 Jan 2023 13:01:33 +0100 Subject: [PATCH 43/46] refactor: pagination param --- spec/requests/api/article_categories_spec.rb | 3 +-- spec/requests/api/financial_transaction_classes_spec.rb | 3 +-- spec/requests/api/financial_transaction_types_spec.rb | 3 +-- spec/requests/api/financial_transactions_spec.rb | 3 +-- spec/requests/api/orders_spec.rb | 4 +--- spec/requests/api/user/financial_transactions_spec.rb | 4 +--- spec/requests/api/user/group_order_articles_spec.rb | 3 +-- spec/support/api_helper.rb | 7 ++++++- 8 files changed, 13 insertions(+), 17 deletions(-) diff --git a/spec/requests/api/article_categories_spec.rb b/spec/requests/api/article_categories_spec.rb index c8b60984..4c079ff2 100644 --- a/spec/requests/api/article_categories_spec.rb +++ b/spec/requests/api/article_categories_spec.rb @@ -7,8 +7,7 @@ describe 'Article Categories', type: :request do get 'article categories' do tags 'Category' produces 'application/json' - parameter name: "per_page", in: :query, type: :integer, required: false - parameter name: "page", in: :query, type: :integer, required: false + pagination_param let(:order_article) { create(:order, article_count: 1).order_articles.first } let(:stock_article) { create(:stock_article) } let(:stock_order_article) { create(:stock_order, article_ids: [stock_article.id]).order_articles.first } diff --git a/spec/requests/api/financial_transaction_classes_spec.rb b/spec/requests/api/financial_transaction_classes_spec.rb index 5482c10b..1eaf046f 100644 --- a/spec/requests/api/financial_transaction_classes_spec.rb +++ b/spec/requests/api/financial_transaction_classes_spec.rb @@ -7,8 +7,7 @@ describe 'Financial Transaction Classes', type: :request do get 'financial transaction classes' do tags 'Category' produces 'application/json' - parameter name: "per_page", in: :query, type: :integer, required: false - parameter name: "page", in: :query, type: :integer, required: false + pagination_param let(:financial_transaction_class) { create(:financial_transaction_class) } response '200', 'success' do diff --git a/spec/requests/api/financial_transaction_types_spec.rb b/spec/requests/api/financial_transaction_types_spec.rb index bdf8a0e1..82a30f83 100644 --- a/spec/requests/api/financial_transaction_types_spec.rb +++ b/spec/requests/api/financial_transaction_types_spec.rb @@ -7,8 +7,7 @@ describe 'Financial Transaction types', type: :request do get 'financial transaction types' do tags 'Category' produces 'application/json' - parameter name: "per_page", in: :query, type: :integer, required: false - parameter name: "page", in: :query, type: :integer, required: false + pagination_param let(:financial_transaction_type) { create(:financial_transaction_type) } response '200', 'success' do schema type: :object, properties: { diff --git a/spec/requests/api/financial_transactions_spec.rb b/spec/requests/api/financial_transactions_spec.rb index 3a741714..1d3ef2b9 100644 --- a/spec/requests/api/financial_transactions_spec.rb +++ b/spec/requests/api/financial_transactions_spec.rb @@ -11,8 +11,7 @@ describe 'Financial Transaction', type: :request do get 'financial transactions' do tags 'Financial Transaction' produces 'application/json' - parameter name: "per_page", in: :query, type: :integer, required: false - parameter name: "page", in: :query, type: :integer, required: false + pagination_param response '200', 'success' do schema type: :object, properties: { diff --git a/spec/requests/api/orders_spec.rb b/spec/requests/api/orders_spec.rb index 10495e3f..c0505d7f 100644 --- a/spec/requests/api/orders_spec.rb +++ b/spec/requests/api/orders_spec.rb @@ -8,9 +8,7 @@ describe 'Orders', type: :request do get 'orders' do tags 'Order' produces 'application/json' - parameter name: "per_page", in: :query, type: :integer, required: false - parameter name: "page", in: :query, type: :integer, required: false - + pagination_param let(:order) { create(:order) } response '200', 'success' do diff --git a/spec/requests/api/user/financial_transactions_spec.rb b/spec/requests/api/user/financial_transactions_spec.rb index d5ff820c..6bbcda47 100644 --- a/spec/requests/api/user/financial_transactions_spec.rb +++ b/spec/requests/api/user/financial_transactions_spec.rb @@ -59,9 +59,7 @@ describe 'User', type: :request do get "financial transactions of the member's ordergroup" do tags 'User', 'Financial Transaction' produces 'application/json' - parameter name: "per_page", in: :query, type: :integer, required: false - parameter name: "page", in: :query, type: :integer, required: false - + pagination_param response '200', 'success' do schema type: :object, properties: { diff --git a/spec/requests/api/user/group_order_articles_spec.rb b/spec/requests/api/user/group_order_articles_spec.rb index bad73084..205a4070 100644 --- a/spec/requests/api/user/group_order_articles_spec.rb +++ b/spec/requests/api/user/group_order_articles_spec.rb @@ -19,8 +19,7 @@ describe 'User', type: :request do get 'group order articles' do tags 'User', 'Order' produces 'application/json' - parameter name: "per_page", in: :query, type: :integer, required: false - parameter name: "page", in: :query, type: :integer, required: false + pagination_param q_ordered_url_param response '200', 'success' do diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 98732a19..25576754 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -71,8 +71,13 @@ module ApiHelper parameter name: :id, in: :path, type: :integer, required: true end + def self.pagination_param + parameter name: :per_page, in: :query, type: :integer, required: false + parameter name: :page, in: :query, type: :integer, required: false + end + def self.q_ordered_url_param - parameter name: 'q', in: :query, required: false, + parameter name: :q, in: :query, required: false, description: "'member' show articles ordered by the user's ordergroup, 'all' by all members, and 'supplier' ordered at the supplier", schema: { '$ref' => '#/components/schemas/q_ordered' } end -- 2.45.2 From 619fdbe958ea029f1745844bd95959f9dcbdf4e0 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 2 Jan 2023 13:05:43 +0100 Subject: [PATCH 44/46] fix: minor foo --- spec/requests/api/order_articles_spec.rb | 4 ++-- spec/requests/api/user/financial_transactions_spec.rb | 5 +---- spec/requests/api/user/users_spec.rb | 2 +- spec/support/api_helper.rb | 7 ++++++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/spec/requests/api/order_articles_spec.rb b/spec/requests/api/order_articles_spec.rb index 2285fff6..e0c8c651 100644 --- a/spec/requests/api/order_articles_spec.rb +++ b/spec/requests/api/order_articles_spec.rb @@ -46,7 +46,7 @@ describe 'Order Articles', type: :request do end end - describe 'supplier' do + describe 'when ordered by supplier' do let(:q) { { q: { ordered: 'supplier' } } } run_test! do |response| @@ -56,7 +56,7 @@ describe 'Order Articles', type: :request do end end - describe 'member' do + describe 'when ordered by member' do let(:q) { { q: { ordered: 'member' } } } run_test! do |response| diff --git a/spec/requests/api/user/financial_transactions_spec.rb b/spec/requests/api/user/financial_transactions_spec.rb index 6bbcda47..4225e1ac 100644 --- a/spec/requests/api/user/financial_transactions_spec.rb +++ b/spec/requests/api/user/financial_transactions_spec.rb @@ -91,10 +91,7 @@ describe 'User', type: :request do response '200', 'success' do schema type: :object, properties: { financial_transaction: { - type: :object, - items: { - '$ref': '#/components/schemas/FinancialTransaction' - } + '$ref': '#/components/schemas/FinancialTransaction' } } let(:id) { ft.id } diff --git a/spec/requests/api/user/users_spec.rb b/spec/requests/api/user/users_spec.rb index 01031180..0d3196bc 100644 --- a/spec/requests/api/user/users_spec.rb +++ b/spec/requests/api/user/users_spec.rb @@ -53,6 +53,7 @@ describe 'User', type: :request do tags 'User', 'Financial Transaction' produces 'application/json' let(:user) { create :user, :ordergroup } + let(:api_scopes) { ['finance:user'] } FinancialTransactionClass.create(name: 'TestTransaction') response 200, 'success' do @@ -93,7 +94,6 @@ describe 'User', type: :request do } } - let(:api_scopes) { ['finance:user'] } run_test! end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 25576754..86e2ca07 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -79,7 +79,12 @@ module ApiHelper def self.q_ordered_url_param parameter name: :q, in: :query, required: false, description: "'member' show articles ordered by the user's ordergroup, 'all' by all members, and 'supplier' ordered at the supplier", - schema: { '$ref' => '#/components/schemas/q_ordered' } + schema: { + type: :object, + properties: { + ordered: { '$ref' => '#/components/schemas/q_ordered' } + } + } end end end -- 2.45.2 From 138b99e6f2056b778deea9c908aeb872c9be63ed Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 2 Jan 2023 13:54:05 +0100 Subject: [PATCH 45/46] fix: missed pagination refactoring --- spec/requests/api/order_articles_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/requests/api/order_articles_spec.rb b/spec/requests/api/order_articles_spec.rb index e0c8c651..6fa792fa 100644 --- a/spec/requests/api/order_articles_spec.rb +++ b/spec/requests/api/order_articles_spec.rb @@ -7,8 +7,7 @@ describe 'Order Articles', type: :request do get 'order articles' do tags 'Order' produces 'application/json' - parameter name: "per_page", in: :query, type: :integer, required: false - parameter name: "page", in: :query, type: :integer, required: false + pagination_param q_ordered_url_param let(:api_scopes) { ['orders:read', 'orders:write'] } -- 2.45.2 From a3452e9d9f7651318f60629941a0189ac3353d79 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 2 Jan 2023 13:55:23 +0100 Subject: [PATCH 46/46] fix: quotes --- spec/requests/api/user/financial_transactions_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/user/financial_transactions_spec.rb b/spec/requests/api/user/financial_transactions_spec.rb index 4225e1ac..4fb69cd6 100644 --- a/spec/requests/api/user/financial_transactions_spec.rb +++ b/spec/requests/api/user/financial_transactions_spec.rb @@ -14,7 +14,7 @@ describe 'User', type: :request do path '/user/financial_transactions' do post 'create new financial transaction (requires enabled self service)' do - tags "Financial Transaction" + tags 'Financial Transaction' consumes 'application/json' produces 'application/json' -- 2.45.2