Commit d28843ba authored by Mikolaj Wawrzyniak's avatar Mikolaj Wawrzyniak

Add starred dashboard relation

In order to store information about users
starred metrics dashboard we need to introduce
new database relation and corresponding model inside app
parent 4edd43ae
# frozen_string_literal: true
module Metrics
class UsersStarredDashboard < ApplicationRecord
self.table_name = 'metrics_users_starred_dashboards'
belongs_to :user, inverse_of: :metrics_users_starred_dashboards
belongs_to :project, inverse_of: :metrics_users_starred_dashboards
validates :user_id, presence: true
validates :project_id, presence: true
validates :dashboard_path, presence: true, length: { maximum: 255 }
validates :dashboard_path, uniqueness: { scope: %i[user_id project_id] }
end
end
...@@ -257,6 +257,7 @@ class Project < ApplicationRecord ...@@ -257,6 +257,7 @@ class Project < ApplicationRecord
has_many :prometheus_alerts, inverse_of: :project has_many :prometheus_alerts, inverse_of: :project
has_many :prometheus_alert_events, inverse_of: :project has_many :prometheus_alert_events, inverse_of: :project
has_many :self_managed_prometheus_alert_events, inverse_of: :project has_many :self_managed_prometheus_alert_events, inverse_of: :project
has_many :metrics_users_starred_dashboards, class_name: 'Metrics::UsersStarredDashboard', inverse_of: :project
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :project has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :project
......
...@@ -167,6 +167,8 @@ class User < ApplicationRecord ...@@ -167,6 +167,8 @@ class User < ApplicationRecord
has_many :term_agreements has_many :term_agreements
belongs_to :accepted_term, class_name: 'ApplicationSetting::Term' belongs_to :accepted_term, class_name: 'ApplicationSetting::Term'
has_many :metrics_users_starred_dashboards, class_name: 'Metrics::UsersStarredDashboard', inverse_of: :user
has_one :status, class_name: 'UserStatus' has_one :status, class_name: 'UserStatus'
has_one :user_preference has_one :user_preference
has_one :user_detail has_one :user_detail
......
---
title: Add database relation to preserve users starred
metrics dashboard information.
merge_request: 29912
author:
type: added
# frozen_string_literal: true
class CreateMetricsUsersStarredDashboard < ActiveRecord::Migration[6.0]
DOWNTIME = false
# limit added in following migration db/migrate/20200424101920_add_text_limit_to_metrics_users_starred_dashboards_dashboard_path.rb
# to allow this migration to be run inside the transaction
# rubocop: disable Migration/AddLimitToTextColumns
def up
create_table :metrics_users_starred_dashboards do |t|
t.timestamps_with_timezone
t.bigint :project_id, null: false
t.bigint :user_id, null: false
t.text :dashboard_path, null: false
t.index :project_id
t.index %i(user_id project_id dashboard_path), name: "idx_metrics_users_starred_dashboard_on_user_project_dashboard", unique: true
end
end
# rubocop: enable Migration/AddLimitToTextColumns
def down
drop_table :metrics_users_starred_dashboards
end
end
# frozen_string_literal: true
class AddForeignKeyFromUsersToMetricsUsersStarredDashboars < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key :metrics_users_starred_dashboards, :users, column: :user_id, on_delete: :cascade
end
def down
with_lock_retries do # rubocop:disable Migration/WithLockRetriesWithoutDdlTransaction
remove_foreign_key_if_exists :metrics_users_starred_dashboards, column: :user_id
end
end
end
# frozen_string_literal: true
class AddForeignKeyFromProjectsToMetricsUsersStarredDashboars < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key :metrics_users_starred_dashboards, :projects, column: :project_id, on_delete: :cascade
end
def down
with_lock_retries do # rubocop:disable Migration/WithLockRetriesWithoutDdlTransaction
remove_foreign_key_if_exists :metrics_users_starred_dashboards, column: :project_id
end
end
end
# frozen_string_literal: true
class AddTextLimitToMetricsUsersStarredDashboardsDashboardPath < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_text_limit :metrics_users_starred_dashboards, :dashboard_path, 255
end
def down
remove_text_limit :metrics_users_starred_dashboards, :dashboard_path
end
end
...@@ -4008,6 +4008,25 @@ CREATE SEQUENCE public.metrics_dashboard_annotations_id_seq ...@@ -4008,6 +4008,25 @@ CREATE SEQUENCE public.metrics_dashboard_annotations_id_seq
ALTER SEQUENCE public.metrics_dashboard_annotations_id_seq OWNED BY public.metrics_dashboard_annotations.id; ALTER SEQUENCE public.metrics_dashboard_annotations_id_seq OWNED BY public.metrics_dashboard_annotations.id;
CREATE TABLE public.metrics_users_starred_dashboards (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
project_id bigint NOT NULL,
user_id bigint NOT NULL,
dashboard_path text NOT NULL,
CONSTRAINT check_79a84a0f57 CHECK ((char_length(dashboard_path) <= 255))
);
CREATE SEQUENCE public.metrics_users_starred_dashboards_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.metrics_users_starred_dashboards_id_seq OWNED BY public.metrics_users_starred_dashboards.id;
CREATE TABLE public.milestone_releases ( CREATE TABLE public.milestone_releases (
milestone_id bigint NOT NULL, milestone_id bigint NOT NULL,
release_id bigint NOT NULL release_id bigint NOT NULL
...@@ -7490,6 +7509,8 @@ ALTER TABLE ONLY public.merge_trains ALTER COLUMN id SET DEFAULT nextval('public ...@@ -7490,6 +7509,8 @@ ALTER TABLE ONLY public.merge_trains ALTER COLUMN id SET DEFAULT nextval('public
ALTER TABLE ONLY public.metrics_dashboard_annotations ALTER COLUMN id SET DEFAULT nextval('public.metrics_dashboard_annotations_id_seq'::regclass); ALTER TABLE ONLY public.metrics_dashboard_annotations ALTER COLUMN id SET DEFAULT nextval('public.metrics_dashboard_annotations_id_seq'::regclass);
ALTER TABLE ONLY public.metrics_users_starred_dashboards ALTER COLUMN id SET DEFAULT nextval('public.metrics_users_starred_dashboards_id_seq'::regclass);
ALTER TABLE ONLY public.milestones ALTER COLUMN id SET DEFAULT nextval('public.milestones_id_seq'::regclass); ALTER TABLE ONLY public.milestones ALTER COLUMN id SET DEFAULT nextval('public.milestones_id_seq'::regclass);
ALTER TABLE ONLY public.namespace_statistics ALTER COLUMN id SET DEFAULT nextval('public.namespace_statistics_id_seq'::regclass); ALTER TABLE ONLY public.namespace_statistics ALTER COLUMN id SET DEFAULT nextval('public.namespace_statistics_id_seq'::regclass);
...@@ -8297,6 +8318,9 @@ ALTER TABLE ONLY public.merge_trains ...@@ -8297,6 +8318,9 @@ ALTER TABLE ONLY public.merge_trains
ALTER TABLE ONLY public.metrics_dashboard_annotations ALTER TABLE ONLY public.metrics_dashboard_annotations
ADD CONSTRAINT metrics_dashboard_annotations_pkey PRIMARY KEY (id); ADD CONSTRAINT metrics_dashboard_annotations_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.metrics_users_starred_dashboards
ADD CONSTRAINT metrics_users_starred_dashboards_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.milestones ALTER TABLE ONLY public.milestones
ADD CONSTRAINT milestones_pkey PRIMARY KEY (id); ADD CONSTRAINT milestones_pkey PRIMARY KEY (id);
...@@ -8812,6 +8836,8 @@ CREATE INDEX idx_merge_requests_on_state_id_and_merge_status ON public.merge_req ...@@ -8812,6 +8836,8 @@ CREATE INDEX idx_merge_requests_on_state_id_and_merge_status ON public.merge_req
CREATE INDEX idx_merge_requests_on_target_project_id_and_iid_opened ON public.merge_requests USING btree (target_project_id, iid) WHERE (state_id = 1); CREATE INDEX idx_merge_requests_on_target_project_id_and_iid_opened ON public.merge_requests USING btree (target_project_id, iid) WHERE (state_id = 1);
CREATE UNIQUE INDEX idx_metrics_users_starred_dashboard_on_user_project_dashboard ON public.metrics_users_starred_dashboards USING btree (user_id, project_id, dashboard_path);
CREATE INDEX idx_mr_cc_diff_files_on_mr_cc_id_and_sha ON public.merge_request_context_commit_diff_files USING btree (merge_request_context_commit_id, sha); CREATE INDEX idx_mr_cc_diff_files_on_mr_cc_id_and_sha ON public.merge_request_context_commit_diff_files USING btree (merge_request_context_commit_id, sha);
CREATE INDEX idx_packages_packages_on_project_id_name_version_package_type ON public.packages_packages USING btree (project_id, name, version, package_type); CREATE INDEX idx_packages_packages_on_project_id_name_version_package_type ON public.packages_packages USING btree (project_id, name, version, package_type);
...@@ -9840,6 +9866,8 @@ CREATE INDEX index_metrics_dashboard_annotations_on_cluster_id_and_3_columns ON ...@@ -9840,6 +9866,8 @@ CREATE INDEX index_metrics_dashboard_annotations_on_cluster_id_and_3_columns ON
CREATE INDEX index_metrics_dashboard_annotations_on_environment_id_and_3_col ON public.metrics_dashboard_annotations USING btree (environment_id, dashboard_path, starting_at, ending_at) WHERE (environment_id IS NOT NULL); CREATE INDEX index_metrics_dashboard_annotations_on_environment_id_and_3_col ON public.metrics_dashboard_annotations USING btree (environment_id, dashboard_path, starting_at, ending_at) WHERE (environment_id IS NOT NULL);
CREATE INDEX index_metrics_users_starred_dashboards_on_project_id ON public.metrics_users_starred_dashboards USING btree (project_id);
CREATE INDEX index_milestone_releases_on_release_id ON public.milestone_releases USING btree (release_id); CREATE INDEX index_milestone_releases_on_release_id ON public.milestone_releases USING btree (release_id);
CREATE INDEX index_milestones_on_description_trigram ON public.milestones USING gin (description public.gin_trgm_ops); CREATE INDEX index_milestones_on_description_trigram ON public.milestones USING gin (description public.gin_trgm_ops);
...@@ -11188,6 +11216,9 @@ ALTER TABLE ONLY public.deployments ...@@ -11188,6 +11216,9 @@ ALTER TABLE ONLY public.deployments
ALTER TABLE ONLY public.gitlab_subscriptions ALTER TABLE ONLY public.gitlab_subscriptions
ADD CONSTRAINT fk_bd0c4019c3 FOREIGN KEY (hosted_plan_id) REFERENCES public.plans(id) ON DELETE CASCADE; ADD CONSTRAINT fk_bd0c4019c3 FOREIGN KEY (hosted_plan_id) REFERENCES public.plans(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.metrics_users_starred_dashboards
ADD CONSTRAINT fk_bd6ae32fac FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.snippets ALTER TABLE ONLY public.snippets
ADD CONSTRAINT fk_be41fd4bb7 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE; ADD CONSTRAINT fk_be41fd4bb7 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
...@@ -11242,6 +11273,9 @@ ALTER TABLE ONLY public.geo_event_log ...@@ -11242,6 +11273,9 @@ ALTER TABLE ONLY public.geo_event_log
ALTER TABLE ONLY public.lists ALTER TABLE ONLY public.lists
ADD CONSTRAINT fk_d6cf4279f7 FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; ADD CONSTRAINT fk_d6cf4279f7 FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.metrics_users_starred_dashboards
ADD CONSTRAINT fk_d76a2b9a8c FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.system_note_metadata ALTER TABLE ONLY public.system_note_metadata
ADD CONSTRAINT fk_d83a918cb1 FOREIGN KEY (note_id) REFERENCES public.notes(id) ON DELETE CASCADE; ADD CONSTRAINT fk_d83a918cb1 FOREIGN KEY (note_id) REFERENCES public.notes(id) ON DELETE CASCADE;
...@@ -13542,6 +13576,7 @@ COPY "schema_migrations" (version) FROM STDIN; ...@@ -13542,6 +13576,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200417145946 20200417145946
20200420104303 20200420104303
20200420104323 20200420104323
20200420115948
20200420162730 20200420162730
20200420172113 20200420172113
20200420172752 20200420172752
...@@ -13554,8 +13589,11 @@ COPY "schema_migrations" (version) FROM STDIN; ...@@ -13554,8 +13589,11 @@ COPY "schema_migrations" (version) FROM STDIN;
20200423080334 20200423080334
20200423080607 20200423080607
20200423081409 20200423081409
20200423081441
20200423081519
20200423101529 20200423101529
20200424050250 20200424050250
20200424101920
20200427064130 20200427064130
\. \.
# frozen_string_literal: true
FactoryBot.define do
factory :metrics_users_starred_dashboard, class: '::Metrics::UsersStarredDashboard' do
dashboard_path { "custom_dashboard.yml" }
user
project
end
end
...@@ -487,6 +487,7 @@ project: ...@@ -487,6 +487,7 @@ project:
- daily_report_results - daily_report_results
- jira_imports - jira_imports
- compliance_framework_setting - compliance_framework_setting
- metrics_users_starred_dashboards
- alert_management_alerts - alert_management_alerts
award_emoji: award_emoji:
- awardable - awardable
......
# frozen_string_literal: true
require 'spec_helper'
describe Metrics::UsersStarredDashboard do
describe 'associations' do
it { is_expected.to belong_to(:project).inverse_of(:metrics_users_starred_dashboards) }
it { is_expected.to belong_to(:user).inverse_of(:metrics_users_starred_dashboards) }
end
describe 'validation' do
subject { build(:metrics_users_starred_dashboard) }
it { is_expected.to validate_presence_of(:user_id) }
it { is_expected.to validate_presence_of(:project_id) }
it { is_expected.to validate_presence_of(:dashboard_path) }
it { is_expected.to validate_length_of(:dashboard_path).is_at_most(255) }
it { is_expected.to validate_uniqueness_of(:dashboard_path).scoped_to(%i[user_id project_id]) }
end
end
...@@ -113,6 +113,7 @@ describe Project do ...@@ -113,6 +113,7 @@ describe Project do
it { is_expected.to have_many(:self_managed_prometheus_alert_events) } it { is_expected.to have_many(:self_managed_prometheus_alert_events) }
it { is_expected.to have_many(:alert_management_alerts) } it { is_expected.to have_many(:alert_management_alerts) }
it { is_expected.to have_many(:jira_imports) } it { is_expected.to have_many(:jira_imports) }
it { is_expected.to have_many(:metrics_users_starred_dashboards).inverse_of(:project) }
it_behaves_like 'model with repository' do it_behaves_like 'model with repository' do
let_it_be(:container) { create(:project, :repository, path: 'somewhere') } let_it_be(:container) { create(:project, :repository, path: 'somewhere') }
......
...@@ -54,6 +54,7 @@ describe User, :do_not_mock_admin_mode do ...@@ -54,6 +54,7 @@ describe User, :do_not_mock_admin_mode do
it { is_expected.to have_many(:reported_abuse_reports).dependent(:destroy).class_name('AbuseReport') } it { is_expected.to have_many(:reported_abuse_reports).dependent(:destroy).class_name('AbuseReport') }
it { is_expected.to have_many(:custom_attributes).class_name('UserCustomAttribute') } it { is_expected.to have_many(:custom_attributes).class_name('UserCustomAttribute') }
it { is_expected.to have_many(:releases).dependent(:nullify) } it { is_expected.to have_many(:releases).dependent(:nullify) }
it { is_expected.to have_many(:metrics_users_starred_dashboards).inverse_of(:user) }
describe "#bio" do describe "#bio" do
it 'syncs bio with `user_details.bio` on create' do it 'syncs bio with `user_details.bio` on create' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment