diff --git a/.rubocop.yml b/.rubocop.yml index c69a64de8..295ae2d66 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,7 +3,7 @@ AllCops: - "vendor/**/*" - "db/schema.rb" UseCache: false - TargetRubyVersion: 2.2 + TargetRubyVersion: 2.4 ##################### Style #################################### diff --git a/Gemfile b/Gemfile index 881bcefca..d6fadf2bc 100644 --- a/Gemfile +++ b/Gemfile @@ -51,7 +51,6 @@ gem 'rgl' # Graph framework for project diagram calculations gem 'nested_form_fields' gem 'ajax-datatables-rails', '~> 0.3.1' gem 'commit_param_routing' # Enables different submit actions in the same form to route to different actions in controller -gem 'kaminari' gem 'i18n-js', '~> 3.0' # Localization in javascript files gem 'roo', '~> 2.7.1' # Spreadsheet parser gem 'wicked_pdf', '~> 1.1.0' diff --git a/app/controllers/api/api_controller.rb b/app/controllers/api/api_controller.rb index 630e7fa4c..4eae4fb8d 100644 --- a/app/controllers/api/api_controller.rb +++ b/app/controllers/api/api_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Api class ApiController < ActionController::API attr_reader :iss @@ -50,7 +52,7 @@ module Api def authenticate if auth_params[:grant_type] == 'password' user = User.find_by_email(auth_params[:email]) - unless user && user.valid_password?(auth_params[:password]) + unless user&.valid_password?(auth_params[:password]) raise StandardError, 'Default: Wrong user password' end payload = { user_id: user.id } diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index ff5eafd77..4c43813e9 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Api module V1 class BaseController < ApiController diff --git a/app/controllers/api/v1/inventories_controller.rb b/app/controllers/api/v1/inventories_controller.rb new file mode 100644 index 000000000..136801caa --- /dev/null +++ b/app/controllers/api/v1/inventories_controller.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Api + module V1 + class InventoriesController < BaseController + before_action :load_team, only: %i(show index) + before_action :load_inventory, only: %i(show) + + def index + inventories = + @team.repositories.page(params[:page]).per(params[:page_size]) + render json: inventories, each_serializer: InventorySerializer + end + + def show + render json: @inventory, serializer: InventorySerializer + end + + private + + def load_team + @team = Team.find(params.require(:team_id)) + return render json: {}, status: :forbidden unless can_read_team?(@team) + end + + def load_inventory + @inventory = @team.repositories.find(params.require(:id)) + end + end + end +end diff --git a/app/controllers/api/v1/inventory_items_controller.rb b/app/controllers/api/v1/inventory_items_controller.rb new file mode 100644 index 000000000..f22f1462f --- /dev/null +++ b/app/controllers/api/v1/inventory_items_controller.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Api + module V1 + class InventoryItemsController < BaseController + before_action :load_team + before_action :load_inventory + + def index + items = + @inventory.repository_rows + .includes(repository_cells: :repository_column) + .includes( + repository_cells: Extends::REPOSITORY_SEARCH_INCLUDES + ).page(params[:page]) + .per(params[:page_size]) + render json: items, + each_serializer: InventoryItemSerializer, + include: :inventory_cells + end + + private + + def load_team + @team = Team.find(params.require(:team_id)) + return render json: {}, status: :forbidden unless can_read_team?(@team) + end + + def load_inventory + @inventory = @team.repositories.find(params.require(:inventory_id)) + end + end + end +end diff --git a/app/controllers/api/v1/teams_controller.rb b/app/controllers/api/v1/teams_controller.rb index 18faa4f61..fdf00d14e 100644 --- a/app/controllers/api/v1/teams_controller.rb +++ b/app/controllers/api/v1/teams_controller.rb @@ -16,7 +16,6 @@ module Api def load_team @team = Team.find(params.require(:id)) - return render json: {}, status: :not_found unless @team return render json: {}, status: :forbidden unless can_read_team?(@team) end end diff --git a/app/models/repository_cell.rb b/app/models/repository_cell.rb index 60224fa9a..ab2759573 100644 --- a/app/models/repository_cell.rb +++ b/app/models/repository_cell.rb @@ -8,22 +8,26 @@ class RepositoryCell < ActiveRecord::Base dependent: :destroy belongs_to :repository_text_value, (lambda do - where(repository_cells: { value_type: 'RepositoryTextValue' }) + includes(:repository_cell) + .where(repository_cells: { value_type: 'RepositoryTextValue' }) end), optional: true, foreign_key: :value_id belongs_to :repository_date_value, (lambda do - where(repository_cells: { value_type: 'RepositoryDateValue' }) + includes(:repository_cell) + .where(repository_cells: { value_type: 'RepositoryDateValue' }) end), optional: true, foreign_key: :value_id belongs_to :repository_list_value, (lambda do - where(repository_cells: { value_type: 'RepositoryListValue' }) + includes(:repository_cell) + .where(repository_cells: { value_type: 'RepositoryListValue' }) end), optional: true, foreign_key: :value_id belongs_to :repository_asset_value, (lambda do - where(repository_cells: { value_type: 'RepositoryAssetValue' }) + includes(:repository_cell) + .where(repository_cells: { value_type: 'RepositoryAssetValue' }) end), optional: true, foreign_key: :value_id diff --git a/app/models/repository_row.rb b/app/models/repository_row.rb index 86b789c03..4daa0aae3 100644 --- a/app/models/repository_row.rb +++ b/app/models/repository_row.rb @@ -10,7 +10,7 @@ class RepositoryRow < ApplicationRecord foreign_key: :last_modified_by_id, class_name: 'User', optional: true - has_many :repository_cells, dependent: :destroy + has_many :repository_cells, -> { order(:id) }, dependent: :destroy has_many :repository_columns, through: :repository_cells has_many :my_module_repository_rows, inverse_of: :repository_row, dependent: :destroy diff --git a/app/serializers/api/v1/inventory_cell_serializer.rb b/app/serializers/api/v1/inventory_cell_serializer.rb new file mode 100644 index 000000000..ff478c9d9 --- /dev/null +++ b/app/serializers/api/v1/inventory_cell_serializer.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Api + module V1 + class InventoryCellSerializer < ActiveModel::Serializer + type :inventory_cells + attributes :id, :data_type, :data + attribute :repository_column_id, key: :column_id + + def data_type + type_id = RepositoryColumn + .data_types[object.repository_column.data_type] + I18n.t("api.v1.inventory_data_types.t#{type_id}") + end + + def data + value = + case object.value_type + when 'RepositoryTextValue' + object.repository_text_value + when 'RepositoryDateValue' + object.repository_date_value + when 'RepositoryListValue' + object.repository_list_value + when 'RepositoryAssetValue' + object.repository_list_value + end + ActiveModelSerializers::SerializableResource.new( + value, + namespace: Api::V1, + adapter: :attribute + ).as_json + end + end + end +end diff --git a/app/serializers/api/v1/inventory_item_serializer.rb b/app/serializers/api/v1/inventory_item_serializer.rb new file mode 100644 index 000000000..05a1b3d90 --- /dev/null +++ b/app/serializers/api/v1/inventory_item_serializer.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Api + module V1 + class InventoryItemSerializer < ActiveModel::Serializer + type :inventory_items + attributes :id, :name + has_many :repository_cells, key: :inventory_cells, + serializer: InventoryCellSerializer, + class_name: 'RepositoryCell' + end + end +end diff --git a/app/serializers/api/v1/inventory_serializer.rb b/app/serializers/api/v1/inventory_serializer.rb new file mode 100644 index 000000000..dfe55f534 --- /dev/null +++ b/app/serializers/api/v1/inventory_serializer.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Api + module V1 + class InventorySerializer < ActiveModel::Serializer + type :inventories + attributes :id, :name + end + end +end diff --git a/app/serializers/api/v1/repository_asset_value_serializer.rb b/app/serializers/api/v1/repository_asset_value_serializer.rb new file mode 100644 index 000000000..be1373efb --- /dev/null +++ b/app/serializers/api/v1/repository_asset_value_serializer.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Api + module V1 + class RepositoryAssetValueSerializer < ActiveModel::Serializer + attributes :file_id, :file_name, :file_size, :url + + def file_id + object.asset&.id + end + + def file_name + object.asset&.file_file_name + end + + def file_size + object.asset&.file_file_size + end + + def url + if !object.asset&.file_present + nil + elsif object.asset&.file&.is_stored_on_s3? + object.asset.presigned_url(download: true) + else + # separate api endpoint for local files download is needed + download_asset_path(object.asset.id) + end + end + end + end +end diff --git a/app/serializers/api/v1/repository_list_value_serializer.rb b/app/serializers/api/v1/repository_list_value_serializer.rb new file mode 100644 index 000000000..6360b529d --- /dev/null +++ b/app/serializers/api/v1/repository_list_value_serializer.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Api + module V1 + class RepositoryListValueSerializer < ActiveModel::Serializer + attribute :formatted, key: :value + attribute :repository_list_item_id, key: :inventory_list_item_id + end + end +end diff --git a/app/serializers/api/v1/repository_text_value_serializer.rb b/app/serializers/api/v1/repository_text_value_serializer.rb new file mode 100644 index 000000000..ea1a51da0 --- /dev/null +++ b/app/serializers/api/v1/repository_text_value_serializer.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Api + module V1 + class RepositoryTextValueSerializer < ActiveModel::Serializer + attribute :formatted, key: :value + end + end +end diff --git a/app/serializers/api/v1/team_serializer.rb b/app/serializers/api/v1/team_serializer.rb index 692b66538..ffe94acc0 100644 --- a/app/serializers/api/v1/team_serializer.rb +++ b/app/serializers/api/v1/team_serializer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Api module V1 class TeamSerializer < ActiveModel::Serializer diff --git a/config/initializers/active_model_serializer.rb b/config/initializers/active_model_serializer.rb index 032c70089..692906d54 100644 --- a/config/initializers/active_model_serializer.rb +++ b/config/initializers/active_model_serializer.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + ActiveModelSerializers.config.adapter = :json_api ActiveModelSerializers.config.key_transform = :unaltered diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb index dc1899682..72b582a0a 100644 --- a/config/initializers/mime_types.rb +++ b/config/initializers/mime_types.rb @@ -2,3 +2,4 @@ # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf +Mime::Type.register 'application/vnd.api+json', :json diff --git a/config/locales/en.yml b/config/locales/en.yml index 8dee84d14..c7440c1de 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1943,6 +1943,12 @@ en: status_ok: "Ok" expired_token: "Token is expired" invalid_token: "Token is invalid" + v1: + inventory_data_types: + t0: "text" + t1: "date" + t2: "list" + t3: "file" Add: "Add" Asset: "File" diff --git a/config/routes.rb b/config/routes.rb index ddca6879a..bc95e9011 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -542,6 +542,9 @@ Rails.application.routes.draw do post 'auth/token', to: 'api#authenticate' namespace :v1 do resources :teams, only: %i(index show) do + resources :inventories, only: %i(index show) do + get 'items', to: 'inventory_items#index' + end end end end diff --git a/db/migrate/20180806115201_change_primary_key_to_bigint_on_repositories.rb b/db/migrate/20180806115201_change_primary_key_to_bigint_on_repositories.rb new file mode 100644 index 000000000..23eba49f8 --- /dev/null +++ b/db/migrate/20180806115201_change_primary_key_to_bigint_on_repositories.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class ChangePrimaryKeyToBigintOnRepositories < ActiveRecord::Migration[5.1] + def up + change_column :repository_rows, :id, :bigint + change_column :repository_columns, :id, :bigint + change_column :repository_cells, :id, :bigint + change_column :repository_cells, :repository_row_id, :bigint + change_column :repository_cells, :value_id, :bigint + change_column :repository_text_values, :id, :bigint + change_column :repository_date_values, :id, :bigint + change_column :my_module_repository_rows, :repository_row_id, :bigint + end + + def down + change_column :repository_rows, :id, :integer + change_column :repository_columns, :id, :integer + change_column :repository_cells, :id, :integer + change_column :repository_cells, :repository_row_id, :integer + change_column :repository_cells, :value_id, :integer + change_column :repository_text_values, :id, :integer + change_column :repository_date_values, :id, :integer + change_column :my_module_repository_rows, :repository_row_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index ce0aa9260..d8a0ddce9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180524091143) do +ActiveRecord::Schema.define(version: 20180806115201) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -181,7 +181,7 @@ ActiveRecord::Schema.define(version: 20180524091143) do end create_table "my_module_repository_rows", id: :serial, force: :cascade do |t| - t.integer "repository_row_id", null: false + t.bigint "repository_row_id", null: false t.integer "my_module_id" t.integer "assigned_by_id", null: false t.datetime "created_at" @@ -379,11 +379,11 @@ ActiveRecord::Schema.define(version: 20180524091143) do t.index ["last_modified_by_id"], name: "index_repository_asset_values_on_last_modified_by_id" end - create_table "repository_cells", id: :serial, force: :cascade do |t| - t.integer "repository_row_id" + create_table "repository_cells", force: :cascade do |t| + t.bigint "repository_row_id" t.integer "repository_column_id" t.string "value_type" - t.integer "value_id" + t.bigint "value_id" t.datetime "created_at" t.datetime "updated_at" t.index ["repository_column_id"], name: "index_repository_cells_on_repository_column_id" @@ -391,7 +391,7 @@ ActiveRecord::Schema.define(version: 20180524091143) do t.index ["value_type", "value_id"], name: "index_repository_cells_on_value_type_and_value_id" end - create_table "repository_columns", id: :serial, force: :cascade do |t| + create_table "repository_columns", force: :cascade do |t| t.integer "repository_id" t.integer "created_by_id", null: false t.string "name" @@ -401,7 +401,7 @@ ActiveRecord::Schema.define(version: 20180524091143) do t.index ["repository_id"], name: "index_repository_columns_on_repository_id" end - create_table "repository_date_values", id: :serial, force: :cascade do |t| + create_table "repository_date_values", force: :cascade do |t| t.datetime "data" t.datetime "created_at" t.datetime "updated_at" @@ -435,7 +435,7 @@ ActiveRecord::Schema.define(version: 20180524091143) do t.index ["repository_list_item_id"], name: "index_repository_list_values_on_repository_list_item_id" end - create_table "repository_rows", id: :serial, force: :cascade do |t| + create_table "repository_rows", force: :cascade do |t| t.integer "repository_id" t.integer "created_by_id", null: false t.integer "last_modified_by_id", null: false @@ -456,7 +456,7 @@ ActiveRecord::Schema.define(version: 20180524091143) do t.index ["user_id"], name: "index_repository_table_states_on_user_id" end - create_table "repository_text_values", id: :serial, force: :cascade do |t| + create_table "repository_text_values", force: :cascade do |t| t.string "data" t.datetime "created_at" t.datetime "updated_at" diff --git a/docker-compose.production.yml b/docker-compose.production.yml index f1fdb456c..0877637cb 100644 --- a/docker-compose.production.yml +++ b/docker-compose.production.yml @@ -2,7 +2,7 @@ version: '2' services: db: container_name: scinote_db_production - image: postgres:9.4 + image: postgres:9.6 volumes: - scinote_production_postgres:/var/lib/postgresql/data diff --git a/docker-compose.yml b/docker-compose.yml index 6d89be949..12186ebb6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '2' services: db: container_name: scinote_db_development - image: postgres:9.4 + image: postgres:9.6 volumes: - scinote_development_postgres:/var/lib/postgresql/data diff --git a/spec/requests/api/v1/inventories_controller_spec.rb b/spec/requests/api/v1/inventories_controller_spec.rb new file mode 100644 index 000000000..bfdbefcc2 --- /dev/null +++ b/spec/requests/api/v1/inventories_controller_spec.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe "Api::V1::InventoriesController", type: :request do + before :all do + @user = create(:user) + @teams = create_list(:team, 2, created_by: @user) + create(:user_team, user: @user, team: @teams.first, role: 2) + + # valid_inventories + create(:repository, name: Faker::Name.unique.name, + created_by: @user, team: @teams.first) + create(:repository, name: Faker::Name.unique.name, + created_by: @user, team: @teams.first) + + # unaccessable_inventories + create(:repository, name: Faker::Name.unique.name, + created_by: @user, team: @teams.second) + create(:repository, name: Faker::Name.unique.name, + created_by: @user, team: @teams.second) + + @valid_headers = + { 'Authorization': 'Bearer ' + generate_token(@user.id) } + end + + describe 'GET inventories, #index' do + it 'Response with correct inventories' do + hash_body = nil + get api_v1_team_inventories_path(team_id: @teams.first.id), + headers: @valid_headers + expect { hash_body = json }.not_to raise_exception + expect(hash_body[:data]).to match( + ActiveModelSerializers::SerializableResource + .new(@teams.first.repositories, + each_serializer: Api::V1::InventorySerializer) + .as_json[:data] + ) + end + + it 'When invalid request, user in not member of the team' do + hash_body = nil + get api_v1_team_inventories_path(team_id: @teams.second.id), + headers: @valid_headers + expect(response).to have_http_status(403) + expect { hash_body = json }.not_to raise_exception + expect(hash_body).to match({}) + end + end + + describe 'GET inventory, #show' do + it 'When valid request, user is member of the team' do + hash_body = nil + get api_v1_team_inventory_path(team_id: @teams.first.id, + id: @teams.first.repositories.first.id), + headers: @valid_headers + expect { hash_body = json }.not_to raise_exception + expect(hash_body[:data]).to match( + ActiveModelSerializers::SerializableResource + .new(@teams.first.repositories.first, + serializer: Api::V1::InventorySerializer) + .as_json[:data] + ) + end + + it 'When invalid request, user in not member of the team' do + hash_body = nil + get api_v1_team_inventory_path(team_id: @teams.second.id, + id: @teams.second.repositories.first.id), + headers: @valid_headers + expect(response).to have_http_status(403) + expect { hash_body = json }.not_to raise_exception + expect(hash_body).to match({}) + end + + it 'When invalid request, non existing inventory' do + hash_body = nil + get api_v1_team_inventory_path(team_id: @teams.first.id, id: 123), + headers: @valid_headers + expect(response).to have_http_status(404) + expect { hash_body = json }.not_to raise_exception + expect(hash_body).to match({}) + end + + it 'When invalid request, repository from another team' do + hash_body = nil + get api_v1_team_inventory_path(team_id: @teams.first.id, + id: @teams.second.repositories.first.id), + headers: @valid_headers + expect(response).to have_http_status(404) + expect { hash_body = json }.not_to raise_exception + expect(hash_body).to match({}) + end + end +end diff --git a/spec/requests/api/v1/inventory_items_controller_spec.rb b/spec/requests/api/v1/inventory_items_controller_spec.rb new file mode 100644 index 000000000..80e28fc80 --- /dev/null +++ b/spec/requests/api/v1/inventory_items_controller_spec.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Api::V1::InventoryItemsController', type: :request do + before :all do + @user = create(:user) + @teams = create_list(:team, 2, created_by: @user) + create(:user_team, user: @user, team: @teams.first, role: 2) + + # valid_inventory + @valid_inventory = create(:repository, name: Faker::Name.unique.name, + created_by: @user, team: @teams.first) + + # unaccessable_inventory + create(:repository, name: Faker::Name.unique.name, + created_by: @user, team: @teams.second) + + text_column = create(:repository_column, name: Faker::Name.unique.name, + repository: @valid_inventory, data_type: :RepositoryTextValue) + list_column = create(:repository_column, name: Faker::Name.unique.name, + repository: @valid_inventory, data_type: :RepositoryListValue) + list_item = + create(:repository_list_item, repository: @valid_inventory, + repository_column: list_column, data: Faker::Name.unique.name) + file_column = create(:repository_column, name: Faker::Name.unique.name, + repository: @valid_inventory, data_type: :RepositoryAssetValue) + asset = create(:asset) + + create_list(:repository_row, 100, repository: @valid_inventory) + + @valid_inventory.repository_rows.each do |row| + create(:repository_text_value, + data: Faker::Name.name, + repository_cell_attributes: + { repository_row: row, repository_column: text_column }) + create(:repository_list_value, repository_list_item: list_item, + repository_cell_attributes: + { repository_row: row, repository_column: list_column }) + create(:repository_asset_value, asset: asset, + repository_cell_attributes: + { repository_row: row, repository_column: file_column }) + end + + @valid_headers = + { 'Authorization': 'Bearer ' + generate_token(@user.id) } + end + + describe 'GET inventory_items, #index' do + it 'Response with correct inventory items, default per page' do + hash_body = nil + get api_v1_team_inventory_items_path( + team_id: @teams.first.id, + inventory_id: @teams.first.repositories.first.id + ), headers: @valid_headers + expect { hash_body = json }.not_to raise_exception + expect(hash_body[:data]).to match( + ActiveModelSerializers::SerializableResource + .new(@valid_inventory.repository_rows.limit(10), + each_serializer: Api::V1::InventoryItemSerializer, + include: :inventory_cells) + .as_json[:data] + ) + expect(hash_body[:included]).to match( + ActiveModelSerializers::SerializableResource + .new(@valid_inventory.repository_rows.limit(10), + each_serializer: Api::V1::InventoryItemSerializer, + include: :inventory_cells) + .as_json[:included] + ) + end + + it 'Response with correct inventory items, 100 per page' do + hash_body = nil + get api_v1_team_inventory_items_path( + team_id: @teams.first.id, + inventory_id: @teams.first.repositories.first.id + ), params: { page_size: 100 }, headers: @valid_headers + expect { hash_body = json }.not_to raise_exception + expect(hash_body[:data]).to match( + ActiveModelSerializers::SerializableResource + .new(@valid_inventory.repository_rows.limit(100), + each_serializer: Api::V1::InventoryItemSerializer, + include: :inventory_cells) + .as_json[:data] + ) + expect(hash_body[:included]).to match( + ActiveModelSerializers::SerializableResource + .new(@valid_inventory.repository_rows.limit(100), + each_serializer: Api::V1::InventoryItemSerializer, + include: :inventory_cells) + .as_json[:included] + ) + end + + it 'When invalid request, user in not member of the team' do + hash_body = nil + get api_v1_team_inventory_items_path( + team_id: @teams.second.id, + inventory_id: @teams.second.repositories.first.id + ), headers: @valid_headers + expect(response).to have_http_status(403) + expect { hash_body = json }.not_to raise_exception + expect(hash_body).to match({}) + end + + it 'When invalid request, non existing inventory' do + hash_body = nil + get api_v1_team_inventory_items_path( + team_id: @teams.first.id, + inventory_id: 123 + ), headers: @valid_headers + expect(response).to have_http_status(404) + expect { hash_body = json }.not_to raise_exception + expect(hash_body).to match({}) + end + + it 'When invalid request, repository from another team' do + hash_body = nil + get api_v1_team_inventory_items_path( + team_id: @teams.first.id, + inventory_id: @teams.second.repositories.first.id + ), headers: @valid_headers + expect(response).to have_http_status(404) + expect { hash_body = json }.not_to raise_exception + expect(hash_body).to match({}) + end + end +end