From a8ad7ef826a7f050f5aa52708465838f6efe91d2 Mon Sep 17 00:00:00 2001 From: Oleksii Kriuchykhin Date: Thu, 2 Dec 2021 14:18:13 +0100 Subject: [PATCH] Add models and controller for repository table filters [SCI-6209] --- .../repository_table_filters_controller.rb | 85 +++++++++++ app/models/repository.rb | 1 + app/models/repository_column.rb | 1 + app/models/repository_table_filter.rb | 9 ++ app/models/repository_table_filter_element.rb | 28 ++++ app/models/user.rb | 1 + ...ository_table_filter_element_serializer.rb | 5 + .../repository_table_filter_serializer.rb | 6 + config/routes.rb | 1 + .../20211123103711_add_repository_filters.rb | 21 +++ db/structure.sql | 138 +++++++++++++++++- 11 files changed, 294 insertions(+), 2 deletions(-) create mode 100644 app/controllers/repository_table_filters_controller.rb create mode 100644 app/models/repository_table_filter.rb create mode 100644 app/models/repository_table_filter_element.rb create mode 100644 app/serializers/repository_table_filter_element_serializer.rb create mode 100644 app/serializers/repository_table_filter_serializer.rb create mode 100644 db/migrate/20211123103711_add_repository_filters.rb diff --git a/app/controllers/repository_table_filters_controller.rb b/app/controllers/repository_table_filters_controller.rb new file mode 100644 index 000000000..588be5bef --- /dev/null +++ b/app/controllers/repository_table_filters_controller.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +class RepositoryTableFiltersController < ApplicationController + include InputSanitizeHelper + + before_action :load_repository + before_action :load_repository_table_filter, only: %i(show update destroy) + before_action :check_read_permissions, except: %i(create update destroy) + before_action :check_create_permissions, only: %i(create) + before_action :check_manage_permissions, only: %i(update destroy) + + def index + render json: @repository.repository_table_filters + end + + def show + render json: @repository_table_filter, include: :repository_table_filter_elements + end + + def create + repository_table_filter = @repository.repository_table_filters.new( + default_columns: repository_table_filter_params[:default_columns], + created_by: current_user + ) + repository_table_filter.transaction do + repository_table_filter.save! + repository_table_filter_params[:custom_columns].each do |custom_column_params| + repository_table_filter.repository_table_filter_elements.create!(custom_column_params) + end + end + if repository_table_filter.persisted? + render json: repository_table_filter + else + render json: repository_table_filter.errors, status: :unprocessable_entity + end + end + + def update + @repository_table_filter.transaction do + @repository_table_filter.default_columns = repository_table_filter_params[:default_columns] + repository_table_filter_params[:custom_columns].each do |custom_column_params| + @repository_table_filter.repository_table_filter_elements + .find_by(repository_column_id: custom_column_params[:repository_column_id]) + .update!(custom_column_params) + end + end + if @repository_table_filter.persisted? + render json: @repository_table_filter + else + render json: repository_table_filter.errors, status: :unprocessable_entity + end + end + + def destroy + @repository_table_filter.destroy! + render body: nil, status: :ok + end + + private + + def load_repository + @repository = Repository.accessible_by_teams(current_team).find_by(id: params[:repository_id]) + render_403 unless can_read_repository?(@repository) + end + + def load_repository_table_filter + @repository_table_filter = @repository.repository_table_filters.find(params[:id]) + end + + def check_read_permissions + render_403 unless can_read_repository?(@repository) + end + + def check_create_permissions + render_403 unless can_manage_repository?(@repository) + end + + def check_manage_permissions + render_403 unless can_manage_repository?(@repository) + end + + def repository_table_filter_params + require(:repository_table_filter).permit(:name, default_columns: [], custom_columns: []) + end +end diff --git a/app/models/repository.rb b/app/models/repository.rb index af00a1012..edba08624 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -24,6 +24,7 @@ class Repository < RepositoryBase class_name: 'RepositorySnapshot', foreign_key: :parent_id, inverse_of: :original_repository + has_many :repository_table_filters, dependent: :destroy before_save :sync_name_with_snapshots, if: :name_changed? after_save :unassign_unshared_items, if: :saved_change_to_permission_level diff --git a/app/models/repository_column.rb b/app/models/repository_column.rb index 16b36d16f..ce56423e1 100644 --- a/app/models/repository_column.rb +++ b/app/models/repository_column.rb @@ -14,6 +14,7 @@ class RepositoryColumn < ApplicationRecord has_many :repository_checklist_items, -> { order('data ASC') }, dependent: :destroy, index_errors: true, inverse_of: :repository_column + has_many :repository_table_filter_elements, dependent: :destroy accepts_nested_attributes_for :repository_status_items, allow_destroy: true accepts_nested_attributes_for :repository_list_items, allow_destroy: true diff --git a/app/models/repository_table_filter.rb b/app/models/repository_table_filter.rb new file mode 100644 index 000000000..9900f9330 --- /dev/null +++ b/app/models/repository_table_filter.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class RepositoryTableFilter < ApplicationRecord + belongs_to :repository, inverse_of: :repository_table_filters + belongs_to :created_by, class_name: 'User', inverse_of: :repository_table_filters + has_many :repository_table_filter_elements, dependent: :destroy + + validates :name, :repository, :created_by, presence: true +end diff --git a/app/models/repository_table_filter_element.rb b/app/models/repository_table_filter_element.rb new file mode 100644 index 000000000..7aa7f5572 --- /dev/null +++ b/app/models/repository_table_filter_element.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class RepositoryTableFilterElement < ApplicationRecord + enum operator: { contains: 0, + doesnt_contain: 1, + empty: 2, + any_of: 3, + none_of: 4, + all_of: 5, + equal_to: 6, + unequal_to: 7, + greater_than: 8, + less_than: 9, + greater_than_or_equal_to: 10, + less_than_or_equal_to: 11, + between: 12, + file_is_attached: 13, + file_is_not_attached: 14, + file_contains: 15 } + + belongs_to :repository_table_filter, inverse_of: :repository_table_filter_elements + belongs_to :repository_column, inverse_of: :repository_table_filter_elements + + validates :repository_column, presence: true, + inclusion: { in: proc { |record| + record.repository_table_filter.repository.repository_columns + } } +end diff --git a/app/models/user.rb b/app/models/user.rb index 2b135122d..a23e6175a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -71,6 +71,7 @@ class User < ApplicationRecord has_many :results, inverse_of: :user has_many :repositories, inverse_of: :user has_many :repository_table_states, inverse_of: :user, dependent: :destroy + has_many :repository_table_filters, inverse_of: :user, dependent: :nullify has_many :steps, inverse_of: :user has_many :reports, inverse_of: :user has_many :created_assets, class_name: 'Asset', foreign_key: 'created_by_id' diff --git a/app/serializers/repository_table_filter_element_serializer.rb b/app/serializers/repository_table_filter_element_serializer.rb new file mode 100644 index 000000000..90c2c98e1 --- /dev/null +++ b/app/serializers/repository_table_filter_element_serializer.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class RepositoryTableFilterElementSerializer < ActiveModel::Serializer + attributes :repository_column_id, :operator, :parameters +end diff --git a/app/serializers/repository_table_filter_serializer.rb b/app/serializers/repository_table_filter_serializer.rb new file mode 100644 index 000000000..1af3f18f1 --- /dev/null +++ b/app/serializers/repository_table_filter_serializer.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class RepositoryTableFilterSerializer < ActiveModel::Serializer + attributes :name, :default_columns + has_many :repository_table_filter_elements, serializer: RepositoryTableFilterElementSerializer +end diff --git a/config/routes.rb b/config/routes.rb index 60706a24c..6fb3f3477 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -589,6 +589,7 @@ Rails.application.routes.draw do get :describe_all end end + resources :repository_table_filters, only: %i(index show create update destroy) resources :repository_rows, only: %i(create show update) do collection do get :print_modal diff --git a/db/migrate/20211123103711_add_repository_filters.rb b/db/migrate/20211123103711_add_repository_filters.rb new file mode 100644 index 000000000..8d41e111d --- /dev/null +++ b/db/migrate/20211123103711_add_repository_filters.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class AddRepositoryFilters < ActiveRecord::Migration[6.1] + def change + create_table :repository_table_filters do |t| + t.string :name, null: false + t.jsonb :default_columns, null: false, default: {} + t.references :repository, index: true + t.references :created_by, index: true, foreign_key: { to_table: :users } + t.timestamps + end + + create_table :repository_table_filter_elements do |t| + t.references :repository_table_filter, index: { name: 'index_on_repository_table_filter_id' } + t.references :repository_column, index: true + t.integer :operator + t.jsonb :parameters, null: false, default: {} + t.timestamps + end + end +end diff --git a/db/structure.sql b/db/structure.sql index 2be419e0c..63f904a09 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -2003,6 +2003,74 @@ CREATE SEQUENCE public.repository_status_values_id_seq ALTER SEQUENCE public.repository_status_values_id_seq OWNED BY public.repository_status_values.id; +-- +-- Name: repository_table_filter_elements; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.repository_table_filter_elements ( + id bigint NOT NULL, + repository_table_filter_id bigint, + repository_column_id bigint, + operator integer, + parameters jsonb DEFAULT '{}'::jsonb NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: repository_table_filter_elements_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.repository_table_filter_elements_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: repository_table_filter_elements_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.repository_table_filter_elements_id_seq OWNED BY public.repository_table_filter_elements.id; + + +-- +-- Name: repository_table_filters; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.repository_table_filters ( + id bigint NOT NULL, + name character varying NOT NULL, + default_columns jsonb DEFAULT '{}'::jsonb NOT NULL, + repository_id bigint, + created_by_id bigint, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: repository_table_filters_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.repository_table_filters_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: repository_table_filters_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.repository_table_filters_id_seq OWNED BY public.repository_table_filters.id; + + -- -- Name: repository_table_states; Type: TABLE; Schema: public; Owner: - -- @@ -3504,6 +3572,20 @@ ALTER TABLE ONLY public.repository_status_items ALTER COLUMN id SET DEFAULT next ALTER TABLE ONLY public.repository_status_values ALTER COLUMN id SET DEFAULT nextval('public.repository_status_values_id_seq'::regclass); +-- +-- Name: repository_table_filter_elements id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.repository_table_filter_elements ALTER COLUMN id SET DEFAULT nextval('public.repository_table_filter_elements_id_seq'::regclass); + + +-- +-- Name: repository_table_filters id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.repository_table_filters ALTER COLUMN id SET DEFAULT nextval('public.repository_table_filters_id_seq'::regclass); + + -- -- Name: repository_table_states id; Type: DEFAULT; Schema: public; Owner: - -- @@ -4159,6 +4241,22 @@ ALTER TABLE ONLY public.repository_status_values ADD CONSTRAINT repository_status_values_pkey PRIMARY KEY (id); +-- +-- Name: repository_table_filter_elements repository_table_filter_elements_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.repository_table_filter_elements + ADD CONSTRAINT repository_table_filter_elements_pkey PRIMARY KEY (id); + + +-- +-- Name: repository_table_filters repository_table_filters_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.repository_table_filters + ADD CONSTRAINT repository_table_filters_pkey PRIMARY KEY (id); + + -- -- Name: repository_table_states repository_table_states_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -4998,6 +5096,13 @@ CREATE INDEX index_on_repository_checklist_item_id ON public.repository_checklis CREATE INDEX index_on_repository_checklist_value_id ON public.repository_checklist_items_values USING btree (repository_checklist_value_id); +-- +-- Name: index_on_repository_table_filter_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_on_repository_table_filter_id ON public.repository_table_filter_elements USING btree (repository_table_filter_id); + + -- -- Name: index_project_folders_on_name; Type: INDEX; Schema: public; Owner: - -- @@ -5642,6 +5747,27 @@ CREATE INDEX index_repository_status_values_on_created_by_id ON public.repositor CREATE INDEX index_repository_status_values_on_last_modified_by_id ON public.repository_status_values USING btree (last_modified_by_id); +-- +-- Name: index_repository_table_filter_elements_on_repository_column_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_repository_table_filter_elements_on_repository_column_id ON public.repository_table_filter_elements USING btree (repository_column_id); + + +-- +-- Name: index_repository_table_filters_on_created_by_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_repository_table_filters_on_created_by_id ON public.repository_table_filters USING btree (created_by_id); + + +-- +-- Name: index_repository_table_filters_on_repository_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_repository_table_filters_on_repository_id ON public.repository_table_filters USING btree (repository_id); + + -- -- Name: index_repository_table_states_on_repository_id; Type: INDEX; Schema: public; Owner: - -- @@ -7225,6 +7351,14 @@ ALTER TABLE ONLY public.protocols ADD CONSTRAINT fk_rails_c2952dc4b7 FOREIGN KEY (added_by_id) REFERENCES public.users(id); +-- +-- Name: repository_table_filters fk_rails_c2b1aff901; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.repository_table_filters + ADD CONSTRAINT fk_rails_c2b1aff901 FOREIGN KEY (created_by_id) REFERENCES public.users(id); + + -- -- Name: active_storage_attachments fk_rails_c3b3935057; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -7781,7 +7915,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20210812095254'), ('20210825112050'), ('20210906132120'), -('20211103115450'); ->>>>>>> features/bmt-search +('20211103115450'), +('20211123103711');