From 89ea6a9931bb232bd391ff4dace6e13deb6dee0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 26 Jan 2018 17:06:52 +0100 Subject: Add Callout model --- app/models/callout.rb | 3 +++ app/models/user.rb | 1 + db/migrate/20180125214301_create_callouts.rb | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 app/models/callout.rb create mode 100644 db/migrate/20180125214301_create_callouts.rb diff --git a/app/models/callout.rb b/app/models/callout.rb new file mode 100644 index 00000000000..b8131beb518 --- /dev/null +++ b/app/models/callout.rb @@ -0,0 +1,3 @@ +class Callout < ActiveRecord::Base + belongs_to :user +end diff --git a/app/models/user.rb b/app/models/user.rb index 9403da98268..b54d44fe80a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -137,6 +137,7 @@ class User < ActiveRecord::Base has_many :assigned_merge_requests, dependent: :nullify, foreign_key: :assignee_id, class_name: "MergeRequest" # rubocop:disable Cop/ActiveRecordDependent has_many :custom_attributes, class_name: 'UserCustomAttribute' + has_many :callouts # # Validations diff --git a/db/migrate/20180125214301_create_callouts.rb b/db/migrate/20180125214301_create_callouts.rb new file mode 100644 index 00000000000..5dc9638a845 --- /dev/null +++ b/db/migrate/20180125214301_create_callouts.rb @@ -0,0 +1,19 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class CreateCallouts < ActiveRecord::Migration + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + def change + create_table :callouts do |t| + t.string :feature_name, null: false + t.boolean :dismissed_state, null: false + t.references :user, index: true, foreign_key: { on_delete: :cascade }, null: false + + t.timestamps_with_timezone null: false + end + + add_index :callouts, :feature_name, unique: true + end +end -- cgit v1.2.1 From 0dab083702ff4364bc25ea29812a4305c58e5a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 26 Jan 2018 17:07:35 +0100 Subject: Add Callout specs --- spec/factories/callouts.rb | 8 ++++++++ spec/models/callout_spec.rb | 9 +++++++++ 2 files changed, 17 insertions(+) create mode 100644 spec/factories/callouts.rb create mode 100644 spec/models/callout_spec.rb diff --git a/spec/factories/callouts.rb b/spec/factories/callouts.rb new file mode 100644 index 00000000000..b8ea879933e --- /dev/null +++ b/spec/factories/callouts.rb @@ -0,0 +1,8 @@ +FactoryBot.define do + factory :callout do + feature_name 'test_callout' + dismissed_state false + + user + end +end diff --git a/spec/models/callout_spec.rb b/spec/models/callout_spec.rb new file mode 100644 index 00000000000..8328ce06139 --- /dev/null +++ b/spec/models/callout_spec.rb @@ -0,0 +1,9 @@ +require 'rails_helper' + +describe Callout do + let(:callout) { create(:callout) } + + describe 'relationships' do + it { is_expected.to belong_to(:user) } + end +end -- cgit v1.2.1 From c4667f87037150a408da5c133e573714807e17b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 26 Jan 2018 22:13:54 +0100 Subject: Implement Callouts controller --- app/controllers/callouts_controller.rb | 27 +++++++++++++++++++++++++++ config/routes.rb | 5 +++++ 2 files changed, 32 insertions(+) create mode 100644 app/controllers/callouts_controller.rb diff --git a/app/controllers/callouts_controller.rb b/app/controllers/callouts_controller.rb new file mode 100644 index 00000000000..a7bccfcce78 --- /dev/null +++ b/app/controllers/callouts_controller.rb @@ -0,0 +1,27 @@ +class CalloutsController < ApplicationController + before_action :callout, only: [:dismiss] + + def dismiss + respond_to do |format| + format.json do + if @callout + @callout.update(dismissed_state: true) + else + Callout.create(feature_name: callout_param, dismissed_state: true, user: current_user) + end + + head :ok + end + end + end + + private + + def callout + @callout = Callout.find_by(user: current_user, feature_name: callout_param) + end + + def callout_param + params.require(:feature_name) + end +end diff --git a/config/routes.rb b/config/routes.rb index f162043dd5e..f768bcebc7e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -90,6 +90,11 @@ Rails.application.routes.draw do # Notification settings resources :notification_settings, only: [:create, :update] + # Callouts + namespace :callouts do + post :dismiss + end + draw :google_api draw :import draw :uploads -- cgit v1.2.1 From bca10385539b44b39c28586d2d795e66a5e5e907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 26 Jan 2018 22:49:20 +0100 Subject: Add CalloutsController specs --- spec/controllers/callouts_controller_spec.rb | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 spec/controllers/callouts_controller_spec.rb diff --git a/spec/controllers/callouts_controller_spec.rb b/spec/controllers/callouts_controller_spec.rb new file mode 100644 index 00000000000..bf2aae190f2 --- /dev/null +++ b/spec/controllers/callouts_controller_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe CalloutsController do + let(:user) { create(:user) } + + before do + sign_in(user) + end + + describe "POST #dismiss" do + subject { post :dismiss, feature_name: 'feature_name', format: :json } + + context 'when callout entry does not exist' do + it 'should create a callout entry with dismissed state' do + expect { subject }.to change { Callout.count }.by(1) + end + + it 'should return success' do + subject + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when callout entry already exists' do + let!(:callout) { create(:callout, feature_name: 'feature_name', user: user) } + + it 'should update it with a dismissed state' do + expect { subject }.to change { callout.reload.dismissed_state }.from(false).to(true) + end + + it 'should return success' do + subject + + expect(response).to have_gitlab_http_status(:ok) + end + end + end +end -- cgit v1.2.1 From 860c7c4bd41ab6353834e8e765f5cd86d93a41c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 26 Jan 2018 23:05:28 +0100 Subject: Update database schema --- db/schema.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/db/schema.rb b/db/schema.rb index 4e82a688725..fc12e5752b3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180115201419) do +ActiveRecord::Schema.define(version: 20180125214301) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -203,6 +203,17 @@ ActiveRecord::Schema.define(version: 20180115201419) do add_index "broadcast_messages", ["starts_at", "ends_at", "id"], name: "index_broadcast_messages_on_starts_at_and_ends_at_and_id", using: :btree + create_table "callouts", force: :cascade do |t| + t.string "feature_name", null: false + t.boolean "dismissed_state", null: false + t.integer "user_id", null: false + t.datetime_with_timezone "created_at", null: false + t.datetime_with_timezone "updated_at", null: false + end + + add_index "callouts", ["feature_name"], name: "index_callouts_on_feature_name", unique: true, using: :btree + add_index "callouts", ["user_id"], name: "index_callouts_on_user_id", using: :btree + create_table "chat_names", force: :cascade do |t| t.integer "user_id", null: false t.integer "service_id", null: false @@ -1924,6 +1935,7 @@ ActiveRecord::Schema.define(version: 20180115201419) do add_index "web_hooks", ["type"], name: "index_web_hooks_on_type", using: :btree add_foreign_key "boards", "projects", name: "fk_f15266b5f9", on_delete: :cascade + add_foreign_key "callouts", "users", on_delete: :cascade add_foreign_key "chat_teams", "namespaces", on_delete: :cascade add_foreign_key "ci_build_trace_section_names", "projects", on_delete: :cascade add_foreign_key "ci_build_trace_sections", "ci_build_trace_section_names", column: "section_name_id", name: "fk_264e112c66", on_delete: :cascade -- cgit v1.2.1 From ec6c5833b62df7ff1fe69d4b874762713b4068a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 27 Jan 2018 17:32:10 +0100 Subject: Implement CalloutsHelper --- app/helpers/callouts_helper.rb | 11 +++++++++ spec/helpers/callouts_helper_spec.rb | 45 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 app/helpers/callouts_helper.rb create mode 100644 spec/helpers/callouts_helper_spec.rb diff --git a/app/helpers/callouts_helper.rb b/app/helpers/callouts_helper.rb new file mode 100644 index 00000000000..e435879ee43 --- /dev/null +++ b/app/helpers/callouts_helper.rb @@ -0,0 +1,11 @@ +module CalloutsHelper + def show_gke_cluster_integration_callout?(kube_feature_name, project) + !user_dismissed?(kube_feature_name) && project.team.master?(current_user) + end + + private + + def user_dismissed?(feature_name) + Callout.find_by(user: current_user, feature_name: feature_name).dismissed_state? + end +end diff --git a/spec/helpers/callouts_helper_spec.rb b/spec/helpers/callouts_helper_spec.rb new file mode 100644 index 00000000000..feabbf33ef6 --- /dev/null +++ b/spec/helpers/callouts_helper_spec.rb @@ -0,0 +1,45 @@ +require "spec_helper" + +describe CalloutsHelper do + let(:user) { create(:user) } + + before do + allow(helper).to receive(:current_user).and_return(user) + end + + describe '.show_gke_cluster_integration_callout?' do + let(:project) { create(:project) } + + subject { helper.show_gke_cluster_integration_callout?('test_name', project) } + + context 'when user has not dismissed' do + before do + allow(helper).to receive(:user_dismissed?).and_return(false) + end + + context 'when user is master' do + before do + allow(project).to receive_message_chain(:team, :master?).and_return(true) + end + + it { is_expected.to be true } + end + + context 'when user is not master' do + before do + allow(project).to receive_message_chain(:team, :master?).and_return(false) + end + + it { is_expected.to be false } + end + end + + context 'when user dismissed' do + before do + allow(helper).to receive(:user_dismissed?).and_return(true) + end + + it { is_expected.to be false } + end + end +end -- cgit v1.2.1 From 8be4f3ecf480b64284bd0d2ed31f59f332df1bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 27 Jan 2018 18:44:14 +0100 Subject: Move Callouts route to - path --- config/routes.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index f768bcebc7e..abd626119ca 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -60,6 +60,11 @@ Rails.application.routes.draw do resources :issues, module: :boards, only: [:index, :update] end + + # Callouts + namespace :callouts do + post :dismiss + end end # Koding route @@ -90,11 +95,6 @@ Rails.application.routes.draw do # Notification settings resources :notification_settings, only: [:create, :update] - # Callouts - namespace :callouts do - post :dismiss - end - draw :google_api draw :import draw :uploads -- cgit v1.2.1 From 977996d2b396c1892a0bcdb386d63e4f78675239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Tue, 30 Jan 2018 00:05:48 +0100 Subject: Add check for guest user --- app/helpers/callouts_helper.rb | 2 +- spec/helpers/callouts_helper_spec.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/helpers/callouts_helper.rb b/app/helpers/callouts_helper.rb index e435879ee43..a27533f30c6 100644 --- a/app/helpers/callouts_helper.rb +++ b/app/helpers/callouts_helper.rb @@ -1,6 +1,6 @@ module CalloutsHelper def show_gke_cluster_integration_callout?(kube_feature_name, project) - !user_dismissed?(kube_feature_name) && project.team.master?(current_user) + current_user && !user_dismissed?(kube_feature_name) && project.team.master?(current_user) end private diff --git a/spec/helpers/callouts_helper_spec.rb b/spec/helpers/callouts_helper_spec.rb index feabbf33ef6..f160aafbd7b 100644 --- a/spec/helpers/callouts_helper_spec.rb +++ b/spec/helpers/callouts_helper_spec.rb @@ -41,5 +41,13 @@ describe CalloutsHelper do it { is_expected.to be false } end + + context 'when the user is not logged in' do + before do + allow(helper).to receive(:current_user).and_return(nil) + end + + it { is_expected.to be_falsey } + end end end -- cgit v1.2.1 From 2cd71eb5f5fc4ae2b1e6385977ec7ef298dc77db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Tue, 30 Jan 2018 00:08:27 +0100 Subject: Add safe navigation for users without callout state --- app/helpers/callouts_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/callouts_helper.rb b/app/helpers/callouts_helper.rb index a27533f30c6..199652b1175 100644 --- a/app/helpers/callouts_helper.rb +++ b/app/helpers/callouts_helper.rb @@ -6,6 +6,6 @@ module CalloutsHelper private def user_dismissed?(feature_name) - Callout.find_by(user: current_user, feature_name: feature_name).dismissed_state? + Callout.find_by(user: current_user, feature_name: feature_name)&.dismissed_state? end end -- cgit v1.2.1 From f2253d48a109a12f00b87f5aaaa42299860315f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Tue, 30 Jan 2018 15:17:15 +0100 Subject: Show GKE cluster callout for project owner as well --- app/helpers/callouts_helper.rb | 4 +++- spec/helpers/callouts_helper_spec.rb | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/helpers/callouts_helper.rb b/app/helpers/callouts_helper.rb index 199652b1175..e65daa572a8 100644 --- a/app/helpers/callouts_helper.rb +++ b/app/helpers/callouts_helper.rb @@ -1,6 +1,8 @@ module CalloutsHelper def show_gke_cluster_integration_callout?(kube_feature_name, project) - current_user && !user_dismissed?(kube_feature_name) && project.team.master?(current_user) + current_user && !user_dismissed?(kube_feature_name) && + (project.team.master?(current_user) || + current_user == project.owner) end private diff --git a/spec/helpers/callouts_helper_spec.rb b/spec/helpers/callouts_helper_spec.rb index f160aafbd7b..8dd97e22477 100644 --- a/spec/helpers/callouts_helper_spec.rb +++ b/spec/helpers/callouts_helper_spec.rb @@ -26,11 +26,21 @@ describe CalloutsHelper do end context 'when user is not master' do - before do - allow(project).to receive_message_chain(:team, :master?).and_return(false) + context 'when the user is owner' do + before do + allow(project).to receive(:owner).and_return(user) + end + + it { is_expected.to be true } end - it { is_expected.to be false } + context 'when the user is not owner' do + before do + allow(project).to receive_message_chain(:team, :master?).and_return(false) + end + + it { is_expected.to be false } + end end end -- cgit v1.2.1 From 4157cad23b5215c5b878f120099b4632ed04ce04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Tue, 30 Jan 2018 15:30:49 +0100 Subject: Extract feature name into constant --- app/helpers/callouts_helper.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/helpers/callouts_helper.rb b/app/helpers/callouts_helper.rb index e65daa572a8..153797450de 100644 --- a/app/helpers/callouts_helper.rb +++ b/app/helpers/callouts_helper.rb @@ -1,6 +1,8 @@ module CalloutsHelper - def show_gke_cluster_integration_callout?(kube_feature_name, project) - current_user && !user_dismissed?(kube_feature_name) && + GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration'.freeze + + def show_gke_cluster_integration_callout?(project) + current_user && !user_dismissed?(GKE_CLUSTER_INTEGRATION) && (project.team.master?(current_user) || current_user == project.owner) end -- cgit v1.2.1 From 4cfe66ae5f2c1f83944999c640c175085008105b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Tue, 30 Jan 2018 16:59:10 +0100 Subject: Fix CalloutsHelper spec subject --- spec/helpers/callouts_helper_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/helpers/callouts_helper_spec.rb b/spec/helpers/callouts_helper_spec.rb index 8dd97e22477..7ec8ca8eb0c 100644 --- a/spec/helpers/callouts_helper_spec.rb +++ b/spec/helpers/callouts_helper_spec.rb @@ -10,7 +10,7 @@ describe CalloutsHelper do describe '.show_gke_cluster_integration_callout?' do let(:project) { create(:project) } - subject { helper.show_gke_cluster_integration_callout?('test_name', project) } + subject { helper.show_gke_cluster_integration_callout?(project) } context 'when user has not dismissed' do before do -- cgit v1.2.1 From 4ff0cfe541739ead870fc9f7708db9b19e5b718c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 1 Feb 2018 21:02:07 +0100 Subject: Add callout priority enum --- app/helpers/callouts_helper.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/helpers/callouts_helper.rb b/app/helpers/callouts_helper.rb index 153797450de..f93df287512 100644 --- a/app/helpers/callouts_helper.rb +++ b/app/helpers/callouts_helper.rb @@ -1,6 +1,11 @@ module CalloutsHelper GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration'.freeze + # Higher value = higher priority + PRIORITY = { + GKE_CLUSTER_INTEGRATION: 0 + }.freeze + def show_gke_cluster_integration_callout?(project) current_user && !user_dismissed?(GKE_CLUSTER_INTEGRATION) && (project.team.master?(current_user) || -- cgit v1.2.1 From ad38e120069748049786373af1c2286cf9c849eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 2 Feb 2018 03:07:33 +0100 Subject: Remove dismissed_state from Callout model --- app/controllers/callouts_controller.rb | 20 ++++++-------------- app/helpers/callouts_helper.rb | 2 +- app/models/callout.rb | 3 +++ db/migrate/20180125214301_create_callouts.rb | 3 +-- db/schema.rb | 3 +-- spec/controllers/callouts_controller_spec.rb | 4 ---- spec/factories/callouts.rb | 1 - spec/models/callout_spec.rb | 9 ++++++++- 8 files changed, 20 insertions(+), 25 deletions(-) diff --git a/app/controllers/callouts_controller.rb b/app/controllers/callouts_controller.rb index a7bccfcce78..e24172edf5d 100644 --- a/app/controllers/callouts_controller.rb +++ b/app/controllers/callouts_controller.rb @@ -1,24 +1,16 @@ class CalloutsController < ApplicationController - before_action :callout, only: [:dismiss] - def dismiss - respond_to do |format| - format.json do - if @callout - @callout.update(dismissed_state: true) - else - Callout.create(feature_name: callout_param, dismissed_state: true, user: current_user) - end - - head :ok - end + if ensure_callout + respond_to { |format| format.json { head :ok } } + else + respond_to { |format| format.json { head :bad_request } } end end private - def callout - @callout = Callout.find_by(user: current_user, feature_name: callout_param) + def ensure_callout + current_user.callouts.find_or_create_by(feature_name: callout_param) end def callout_param diff --git a/app/helpers/callouts_helper.rb b/app/helpers/callouts_helper.rb index f93df287512..3841d288f52 100644 --- a/app/helpers/callouts_helper.rb +++ b/app/helpers/callouts_helper.rb @@ -15,6 +15,6 @@ module CalloutsHelper private def user_dismissed?(feature_name) - Callout.find_by(user: current_user, feature_name: feature_name)&.dismissed_state? + current_user&.callouts&.find_by(feature_name: feature_name) end end diff --git a/app/models/callout.rb b/app/models/callout.rb index b8131beb518..c8f41a39cf3 100644 --- a/app/models/callout.rb +++ b/app/models/callout.rb @@ -1,3 +1,6 @@ class Callout < ActiveRecord::Base belongs_to :user + + validates :user, presence: true + validates :feature_name, presence: true, uniqueness: { scope: :user_id } end diff --git a/db/migrate/20180125214301_create_callouts.rb b/db/migrate/20180125214301_create_callouts.rb index 5dc9638a845..b6749b4cfe6 100644 --- a/db/migrate/20180125214301_create_callouts.rb +++ b/db/migrate/20180125214301_create_callouts.rb @@ -8,12 +8,11 @@ class CreateCallouts < ActiveRecord::Migration def change create_table :callouts do |t| t.string :feature_name, null: false - t.boolean :dismissed_state, null: false t.references :user, index: true, foreign_key: { on_delete: :cascade }, null: false t.timestamps_with_timezone null: false end - add_index :callouts, :feature_name, unique: true + add_index :callouts, [:user_id, :feature_name], unique: true end end diff --git a/db/schema.rb b/db/schema.rb index fc12e5752b3..1b837db4e8d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -205,13 +205,12 @@ ActiveRecord::Schema.define(version: 20180125214301) do create_table "callouts", force: :cascade do |t| t.string "feature_name", null: false - t.boolean "dismissed_state", null: false t.integer "user_id", null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false end - add_index "callouts", ["feature_name"], name: "index_callouts_on_feature_name", unique: true, using: :btree + add_index "callouts", ["user_id", "feature_name"], name: "index_callouts_on_user_id_and_feature_name", unique: true, using: :btree add_index "callouts", ["user_id"], name: "index_callouts_on_user_id", using: :btree create_table "chat_names", force: :cascade do |t| diff --git a/spec/controllers/callouts_controller_spec.rb b/spec/controllers/callouts_controller_spec.rb index bf2aae190f2..7a183d757a1 100644 --- a/spec/controllers/callouts_controller_spec.rb +++ b/spec/controllers/callouts_controller_spec.rb @@ -25,10 +25,6 @@ describe CalloutsController do context 'when callout entry already exists' do let!(:callout) { create(:callout, feature_name: 'feature_name', user: user) } - it 'should update it with a dismissed state' do - expect { subject }.to change { callout.reload.dismissed_state }.from(false).to(true) - end - it 'should return success' do subject diff --git a/spec/factories/callouts.rb b/spec/factories/callouts.rb index b8ea879933e..f28df49b00a 100644 --- a/spec/factories/callouts.rb +++ b/spec/factories/callouts.rb @@ -1,7 +1,6 @@ FactoryBot.define do factory :callout do feature_name 'test_callout' - dismissed_state false user end diff --git a/spec/models/callout_spec.rb b/spec/models/callout_spec.rb index 8328ce06139..29299678ebc 100644 --- a/spec/models/callout_spec.rb +++ b/spec/models/callout_spec.rb @@ -1,9 +1,16 @@ require 'rails_helper' describe Callout do - let(:callout) { create(:callout) } + let!(:callout) { create(:callout) } describe 'relationships' do it { is_expected.to belong_to(:user) } end + + describe 'validations' do + it { is_expected.to validate_presence_of(:user) } + + it { is_expected.to validate_presence_of(:feature_name) } + it { is_expected.to validate_uniqueness_of(:feature_name).scoped_to(:user_id) } + end end -- cgit v1.2.1 From 8f942a0534384f73cfa8686a0c67ec6451c5c39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 2 Feb 2018 03:39:07 +0100 Subject: Use policies instead of role checks in ClustersHelper --- app/helpers/callouts_helper.rb | 3 +-- spec/helpers/callouts_helper_spec.rb | 24 ++++++++---------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/app/helpers/callouts_helper.rb b/app/helpers/callouts_helper.rb index 3841d288f52..168b731ae89 100644 --- a/app/helpers/callouts_helper.rb +++ b/app/helpers/callouts_helper.rb @@ -8,8 +8,7 @@ module CalloutsHelper def show_gke_cluster_integration_callout?(project) current_user && !user_dismissed?(GKE_CLUSTER_INTEGRATION) && - (project.team.master?(current_user) || - current_user == project.owner) + can?(current_user, :create_cluster, project) end private diff --git a/spec/helpers/callouts_helper_spec.rb b/spec/helpers/callouts_helper_spec.rb index 7ec8ca8eb0c..d0a5addc231 100644 --- a/spec/helpers/callouts_helper_spec.rb +++ b/spec/helpers/callouts_helper_spec.rb @@ -17,30 +17,22 @@ describe CalloutsHelper do allow(helper).to receive(:user_dismissed?).and_return(false) end - context 'when user is master' do + context 'when user can create a cluster' do before do - allow(project).to receive_message_chain(:team, :master?).and_return(true) + allow(helper).to receive(:can?).with(anything, :create_cluster, anything) + .and_return(true) end it { is_expected.to be true } end - context 'when user is not master' do - context 'when the user is owner' do - before do - allow(project).to receive(:owner).and_return(user) - end - - it { is_expected.to be true } + context 'when user can not create a cluster' do + before do + allow(helper).to receive(:can?).with(anything, :create_cluster, anything) + .and_return(false) end - context 'when the user is not owner' do - before do - allow(project).to receive_message_chain(:team, :master?).and_return(false) - end - - it { is_expected.to be false } - end + it { is_expected.to be false } end end -- cgit v1.2.1 From 1dbcd5ec47980e8c2a38630caec6ccf93d142285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 2 Feb 2018 22:23:26 +0100 Subject: Refactor CalloutsController --- app/controllers/callouts_controller.rb | 10 +++++++--- config/routes.rb | 4 +--- spec/controllers/callouts_controller_spec.rb | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/controllers/callouts_controller.rb b/app/controllers/callouts_controller.rb index e24172edf5d..0fffad3a927 100644 --- a/app/controllers/callouts_controller.rb +++ b/app/controllers/callouts_controller.rb @@ -1,9 +1,13 @@ class CalloutsController < ApplicationController - def dismiss + def create if ensure_callout - respond_to { |format| format.json { head :ok } } + respond_to do |format| + format.json { head :ok } + end else - respond_to { |format| format.json { head :bad_request } } + respond_to do |format| + format.json { head :bad_request } + end end end diff --git a/config/routes.rb b/config/routes.rb index abd626119ca..827de9d5b40 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -62,9 +62,7 @@ Rails.application.routes.draw do end # Callouts - namespace :callouts do - post :dismiss - end + resources :callouts, only: [:create] end # Koding route diff --git a/spec/controllers/callouts_controller_spec.rb b/spec/controllers/callouts_controller_spec.rb index 7a183d757a1..d4879832ef3 100644 --- a/spec/controllers/callouts_controller_spec.rb +++ b/spec/controllers/callouts_controller_spec.rb @@ -7,8 +7,8 @@ describe CalloutsController do sign_in(user) end - describe "POST #dismiss" do - subject { post :dismiss, feature_name: 'feature_name', format: :json } + describe "POST #create" do + subject { post :create, feature_name: 'feature_name', format: :json } context 'when callout entry does not exist' do it 'should create a callout entry with dismissed state' do -- cgit v1.2.1 From 838cc0907c963a025553d639283b3bbf8140dae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 2 Feb 2018 22:25:01 +0100 Subject: Remove timestamps from Callouts --- db/migrate/20180125214301_create_callouts.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/db/migrate/20180125214301_create_callouts.rb b/db/migrate/20180125214301_create_callouts.rb index b6749b4cfe6..bce3d808efd 100644 --- a/db/migrate/20180125214301_create_callouts.rb +++ b/db/migrate/20180125214301_create_callouts.rb @@ -9,8 +9,6 @@ class CreateCallouts < ActiveRecord::Migration create_table :callouts do |t| t.string :feature_name, null: false t.references :user, index: true, foreign_key: { on_delete: :cascade }, null: false - - t.timestamps_with_timezone null: false end add_index :callouts, [:user_id, :feature_name], unique: true -- cgit v1.2.1 From 648826721f13ee4309a11638e538d96006648b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 2 Feb 2018 22:51:03 +0100 Subject: Rename Callout to UserCallout --- app/controllers/callouts_controller.rb | 23 ---------- app/controllers/user_callouts_controller.rb | 23 ++++++++++ app/helpers/callouts_helper.rb | 19 -------- app/helpers/user_callouts_helper.rb | 19 ++++++++ app/models/callout.rb | 6 --- app/models/user.rb | 2 +- app/models/user_callout.rb | 6 +++ config/routes.rb | 4 +- db/migrate/20180125214301_create_callouts.rb | 16 ------- db/migrate/20180125214301_create_user_callouts.rb | 16 +++++++ db/schema.rb | 20 ++++----- spec/controllers/callouts_controller_spec.rb | 35 --------------- spec/controllers/user_callouts_controller_spec.rb | 35 +++++++++++++++ spec/factories/callouts.rb | 7 --- spec/factories/user_callouts.rb | 7 +++ spec/helpers/callouts_helper_spec.rb | 55 ----------------------- spec/helpers/user_callouts_helper_spec.rb | 55 +++++++++++++++++++++++ spec/models/callout_spec.rb | 16 ------- spec/models/user_callout_spec.rb | 16 +++++++ 19 files changed, 189 insertions(+), 191 deletions(-) delete mode 100644 app/controllers/callouts_controller.rb create mode 100644 app/controllers/user_callouts_controller.rb delete mode 100644 app/helpers/callouts_helper.rb create mode 100644 app/helpers/user_callouts_helper.rb delete mode 100644 app/models/callout.rb create mode 100644 app/models/user_callout.rb delete mode 100644 db/migrate/20180125214301_create_callouts.rb create mode 100644 db/migrate/20180125214301_create_user_callouts.rb delete mode 100644 spec/controllers/callouts_controller_spec.rb create mode 100644 spec/controllers/user_callouts_controller_spec.rb delete mode 100644 spec/factories/callouts.rb create mode 100644 spec/factories/user_callouts.rb delete mode 100644 spec/helpers/callouts_helper_spec.rb create mode 100644 spec/helpers/user_callouts_helper_spec.rb delete mode 100644 spec/models/callout_spec.rb create mode 100644 spec/models/user_callout_spec.rb diff --git a/app/controllers/callouts_controller.rb b/app/controllers/callouts_controller.rb deleted file mode 100644 index 0fffad3a927..00000000000 --- a/app/controllers/callouts_controller.rb +++ /dev/null @@ -1,23 +0,0 @@ -class CalloutsController < ApplicationController - def create - if ensure_callout - respond_to do |format| - format.json { head :ok } - end - else - respond_to do |format| - format.json { head :bad_request } - end - end - end - - private - - def ensure_callout - current_user.callouts.find_or_create_by(feature_name: callout_param) - end - - def callout_param - params.require(:feature_name) - end -end diff --git a/app/controllers/user_callouts_controller.rb b/app/controllers/user_callouts_controller.rb new file mode 100644 index 00000000000..69dc444f13a --- /dev/null +++ b/app/controllers/user_callouts_controller.rb @@ -0,0 +1,23 @@ +class UserCalloutsController < ApplicationController + def create + if ensure_callout + respond_to do |format| + format.json { head :ok } + end + else + respond_to do |format| + format.json { head :bad_request } + end + end + end + + private + + def ensure_callout + current_user.callouts.find_or_create_by(feature_name: callout_param) + end + + def callout_param + params.require(:feature_name) + end +end diff --git a/app/helpers/callouts_helper.rb b/app/helpers/callouts_helper.rb deleted file mode 100644 index 168b731ae89..00000000000 --- a/app/helpers/callouts_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -module CalloutsHelper - GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration'.freeze - - # Higher value = higher priority - PRIORITY = { - GKE_CLUSTER_INTEGRATION: 0 - }.freeze - - def show_gke_cluster_integration_callout?(project) - current_user && !user_dismissed?(GKE_CLUSTER_INTEGRATION) && - can?(current_user, :create_cluster, project) - end - - private - - def user_dismissed?(feature_name) - current_user&.callouts&.find_by(feature_name: feature_name) - end -end diff --git a/app/helpers/user_callouts_helper.rb b/app/helpers/user_callouts_helper.rb new file mode 100644 index 00000000000..3725545d4cc --- /dev/null +++ b/app/helpers/user_callouts_helper.rb @@ -0,0 +1,19 @@ +module UserCalloutsHelper + GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration'.freeze + + # Higher value = higher priority + PRIORITY = { + GKE_CLUSTER_INTEGRATION: 0 + }.freeze + + def show_gke_cluster_integration_callout?(project) + current_user && !user_dismissed?(GKE_CLUSTER_INTEGRATION) && + can?(current_user, :create_cluster, project) + end + + private + + def user_dismissed?(feature_name) + current_user&.callouts&.find_by(feature_name: feature_name) + end +end diff --git a/app/models/callout.rb b/app/models/callout.rb deleted file mode 100644 index c8f41a39cf3..00000000000 --- a/app/models/callout.rb +++ /dev/null @@ -1,6 +0,0 @@ -class Callout < ActiveRecord::Base - belongs_to :user - - validates :user, presence: true - validates :feature_name, presence: true, uniqueness: { scope: :user_id } -end diff --git a/app/models/user.rb b/app/models/user.rb index b54d44fe80a..587ee71e812 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -137,7 +137,7 @@ class User < ActiveRecord::Base has_many :assigned_merge_requests, dependent: :nullify, foreign_key: :assignee_id, class_name: "MergeRequest" # rubocop:disable Cop/ActiveRecordDependent has_many :custom_attributes, class_name: 'UserCustomAttribute' - has_many :callouts + has_many :callouts, class_name: 'UserCallout' # # Validations diff --git a/app/models/user_callout.rb b/app/models/user_callout.rb new file mode 100644 index 00000000000..8b31aa6fa5c --- /dev/null +++ b/app/models/user_callout.rb @@ -0,0 +1,6 @@ +class UserCallout < ActiveRecord::Base + belongs_to :user + + validates :user, presence: true + validates :feature_name, presence: true, uniqueness: { scope: :user_id } +end diff --git a/config/routes.rb b/config/routes.rb index 827de9d5b40..e72ea1881cd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -61,8 +61,8 @@ Rails.application.routes.draw do resources :issues, module: :boards, only: [:index, :update] end - # Callouts - resources :callouts, only: [:create] + # UserCallouts + resources :user_callouts, only: [:create] end # Koding route diff --git a/db/migrate/20180125214301_create_callouts.rb b/db/migrate/20180125214301_create_callouts.rb deleted file mode 100644 index bce3d808efd..00000000000 --- a/db/migrate/20180125214301_create_callouts.rb +++ /dev/null @@ -1,16 +0,0 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - -class CreateCallouts < ActiveRecord::Migration - # Set this constant to true if this migration requires downtime. - DOWNTIME = false - - def change - create_table :callouts do |t| - t.string :feature_name, null: false - t.references :user, index: true, foreign_key: { on_delete: :cascade }, null: false - end - - add_index :callouts, [:user_id, :feature_name], unique: true - end -end diff --git a/db/migrate/20180125214301_create_user_callouts.rb b/db/migrate/20180125214301_create_user_callouts.rb new file mode 100644 index 00000000000..945f4181274 --- /dev/null +++ b/db/migrate/20180125214301_create_user_callouts.rb @@ -0,0 +1,16 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class CreateUserCallouts < ActiveRecord::Migration + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + def change + create_table :user_callouts do |t| + t.string :feature_name, null: false + t.references :user, index: true, foreign_key: { on_delete: :cascade }, null: false + end + + add_index :user_callouts, [:user_id, :feature_name], unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 1b837db4e8d..46e4b6d2188 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -203,16 +203,6 @@ ActiveRecord::Schema.define(version: 20180125214301) do add_index "broadcast_messages", ["starts_at", "ends_at", "id"], name: "index_broadcast_messages_on_starts_at_and_ends_at_and_id", using: :btree - create_table "callouts", force: :cascade do |t| - t.string "feature_name", null: false - t.integer "user_id", null: false - t.datetime_with_timezone "created_at", null: false - t.datetime_with_timezone "updated_at", null: false - end - - add_index "callouts", ["user_id", "feature_name"], name: "index_callouts_on_user_id_and_feature_name", unique: true, using: :btree - add_index "callouts", ["user_id"], name: "index_callouts_on_user_id", using: :btree - create_table "chat_names", force: :cascade do |t| t.integer "user_id", null: false t.integer "service_id", null: false @@ -1779,6 +1769,14 @@ ActiveRecord::Schema.define(version: 20180125214301) do add_index "user_agent_details", ["subject_id", "subject_type"], name: "index_user_agent_details_on_subject_id_and_subject_type", using: :btree + create_table "user_callouts", force: :cascade do |t| + t.string "feature_name", null: false + t.integer "user_id", null: false + end + + add_index "user_callouts", ["user_id", "feature_name"], name: "index_user_callouts_on_user_id_and_feature_name", unique: true, using: :btree + add_index "user_callouts", ["user_id"], name: "index_user_callouts_on_user_id", using: :btree + create_table "user_custom_attributes", force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false @@ -1934,7 +1932,6 @@ ActiveRecord::Schema.define(version: 20180125214301) do add_index "web_hooks", ["type"], name: "index_web_hooks_on_type", using: :btree add_foreign_key "boards", "projects", name: "fk_f15266b5f9", on_delete: :cascade - add_foreign_key "callouts", "users", on_delete: :cascade add_foreign_key "chat_teams", "namespaces", on_delete: :cascade add_foreign_key "ci_build_trace_section_names", "projects", on_delete: :cascade add_foreign_key "ci_build_trace_sections", "ci_build_trace_section_names", column: "section_name_id", name: "fk_264e112c66", on_delete: :cascade @@ -2051,6 +2048,7 @@ ActiveRecord::Schema.define(version: 20180125214301) do add_foreign_key "todos", "projects", name: "fk_45054f9c45", on_delete: :cascade add_foreign_key "trending_projects", "projects", on_delete: :cascade add_foreign_key "u2f_registrations", "users" + add_foreign_key "user_callouts", "users", on_delete: :cascade add_foreign_key "user_custom_attributes", "users", on_delete: :cascade add_foreign_key "user_synced_attributes_metadata", "users", on_delete: :cascade add_foreign_key "users_star_projects", "projects", name: "fk_22cd27ddfc", on_delete: :cascade diff --git a/spec/controllers/callouts_controller_spec.rb b/spec/controllers/callouts_controller_spec.rb deleted file mode 100644 index d4879832ef3..00000000000 --- a/spec/controllers/callouts_controller_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'spec_helper' - -describe CalloutsController do - let(:user) { create(:user) } - - before do - sign_in(user) - end - - describe "POST #create" do - subject { post :create, feature_name: 'feature_name', format: :json } - - context 'when callout entry does not exist' do - it 'should create a callout entry with dismissed state' do - expect { subject }.to change { Callout.count }.by(1) - end - - it 'should return success' do - subject - - expect(response).to have_gitlab_http_status(:ok) - end - end - - context 'when callout entry already exists' do - let!(:callout) { create(:callout, feature_name: 'feature_name', user: user) } - - it 'should return success' do - subject - - expect(response).to have_gitlab_http_status(:ok) - end - end - end -end diff --git a/spec/controllers/user_callouts_controller_spec.rb b/spec/controllers/user_callouts_controller_spec.rb new file mode 100644 index 00000000000..ac295aa72bb --- /dev/null +++ b/spec/controllers/user_callouts_controller_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe UserCalloutsController do + let(:user) { create(:user) } + + before do + sign_in(user) + end + + describe "POST #create" do + subject { post :create, feature_name: 'feature_name', format: :json } + + context 'when callout entry does not exist' do + it 'should create a callout entry with dismissed state' do + expect { subject }.to change { UserCallout.count }.by(1) + end + + it 'should return success' do + subject + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when callout entry already exists' do + let!(:callout) { create(:user_callout, feature_name: 'feature_name', user: user) } + + it 'should return success' do + subject + + expect(response).to have_gitlab_http_status(:ok) + end + end + end +end diff --git a/spec/factories/callouts.rb b/spec/factories/callouts.rb deleted file mode 100644 index f28df49b00a..00000000000 --- a/spec/factories/callouts.rb +++ /dev/null @@ -1,7 +0,0 @@ -FactoryBot.define do - factory :callout do - feature_name 'test_callout' - - user - end -end diff --git a/spec/factories/user_callouts.rb b/spec/factories/user_callouts.rb new file mode 100644 index 00000000000..ae83d65da2e --- /dev/null +++ b/spec/factories/user_callouts.rb @@ -0,0 +1,7 @@ +FactoryBot.define do + factory :user_callout do + feature_name 'test_callout' + + user + end +end diff --git a/spec/helpers/callouts_helper_spec.rb b/spec/helpers/callouts_helper_spec.rb deleted file mode 100644 index d0a5addc231..00000000000 --- a/spec/helpers/callouts_helper_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -require "spec_helper" - -describe CalloutsHelper do - let(:user) { create(:user) } - - before do - allow(helper).to receive(:current_user).and_return(user) - end - - describe '.show_gke_cluster_integration_callout?' do - let(:project) { create(:project) } - - subject { helper.show_gke_cluster_integration_callout?(project) } - - context 'when user has not dismissed' do - before do - allow(helper).to receive(:user_dismissed?).and_return(false) - end - - context 'when user can create a cluster' do - before do - allow(helper).to receive(:can?).with(anything, :create_cluster, anything) - .and_return(true) - end - - it { is_expected.to be true } - end - - context 'when user can not create a cluster' do - before do - allow(helper).to receive(:can?).with(anything, :create_cluster, anything) - .and_return(false) - end - - it { is_expected.to be false } - end - end - - context 'when user dismissed' do - before do - allow(helper).to receive(:user_dismissed?).and_return(true) - end - - it { is_expected.to be false } - end - - context 'when the user is not logged in' do - before do - allow(helper).to receive(:current_user).and_return(nil) - end - - it { is_expected.to be_falsey } - end - end -end diff --git a/spec/helpers/user_callouts_helper_spec.rb b/spec/helpers/user_callouts_helper_spec.rb new file mode 100644 index 00000000000..42c2e7827b2 --- /dev/null +++ b/spec/helpers/user_callouts_helper_spec.rb @@ -0,0 +1,55 @@ +require "spec_helper" + +describe UserCalloutsHelper do + let(:user) { create(:user) } + + before do + allow(helper).to receive(:current_user).and_return(user) + end + + describe '.show_gke_cluster_integration_callout?' do + let(:project) { create(:project) } + + subject { helper.show_gke_cluster_integration_callout?(project) } + + context 'when user has not dismissed' do + before do + allow(helper).to receive(:user_dismissed?).and_return(false) + end + + context 'when user can create a cluster' do + before do + allow(helper).to receive(:can?).with(anything, :create_cluster, anything) + .and_return(true) + end + + it { is_expected.to be true } + end + + context 'when user can not create a cluster' do + before do + allow(helper).to receive(:can?).with(anything, :create_cluster, anything) + .and_return(false) + end + + it { is_expected.to be false } + end + end + + context 'when user dismissed' do + before do + allow(helper).to receive(:user_dismissed?).and_return(true) + end + + it { is_expected.to be false } + end + + context 'when the user is not logged in' do + before do + allow(helper).to receive(:current_user).and_return(nil) + end + + it { is_expected.to be_falsey } + end + end +end diff --git a/spec/models/callout_spec.rb b/spec/models/callout_spec.rb deleted file mode 100644 index 29299678ebc..00000000000 --- a/spec/models/callout_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'rails_helper' - -describe Callout do - let!(:callout) { create(:callout) } - - describe 'relationships' do - it { is_expected.to belong_to(:user) } - end - - describe 'validations' do - it { is_expected.to validate_presence_of(:user) } - - it { is_expected.to validate_presence_of(:feature_name) } - it { is_expected.to validate_uniqueness_of(:feature_name).scoped_to(:user_id) } - end -end diff --git a/spec/models/user_callout_spec.rb b/spec/models/user_callout_spec.rb new file mode 100644 index 00000000000..b39d12e48ac --- /dev/null +++ b/spec/models/user_callout_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +describe UserCallout do + let!(:callout) { create(:user_callout) } + + describe 'relationships' do + it { is_expected.to belong_to(:user) } + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:user) } + + it { is_expected.to validate_presence_of(:feature_name) } + it { is_expected.to validate_uniqueness_of(:feature_name).scoped_to(:user_id) } + end +end -- cgit v1.2.1 From 20714ee90232b5577fc99f2a773ddccf71482c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 3 Feb 2018 00:16:24 +0100 Subject: Change UserCallout feautre_name to enum --- app/controllers/user_callouts_controller.rb | 6 +++- app/helpers/user_callouts_helper.rb | 5 ---- app/models/user_callout.rb | 9 +++++- db/migrate/20180125214301_create_user_callouts.rb | 2 +- db/schema.rb | 2 +- spec/controllers/user_callouts_controller_spec.rb | 36 ++++++++++++++++------- spec/factories/user_callouts.rb | 2 +- spec/models/user_callout_spec.rb | 2 +- 8 files changed, 42 insertions(+), 22 deletions(-) diff --git a/app/controllers/user_callouts_controller.rb b/app/controllers/user_callouts_controller.rb index 69dc444f13a..aa048a9a1fc 100644 --- a/app/controllers/user_callouts_controller.rb +++ b/app/controllers/user_callouts_controller.rb @@ -1,6 +1,6 @@ class UserCalloutsController < ApplicationController def create - if ensure_callout + if check_feature_name && ensure_callout respond_to do |format| format.json { head :ok } end @@ -13,6 +13,10 @@ class UserCalloutsController < ApplicationController private + def check_feature_name + UserCallout.feature_names.keys.include?(callout_param) + end + def ensure_callout current_user.callouts.find_or_create_by(feature_name: callout_param) end diff --git a/app/helpers/user_callouts_helper.rb b/app/helpers/user_callouts_helper.rb index 3725545d4cc..a292f676331 100644 --- a/app/helpers/user_callouts_helper.rb +++ b/app/helpers/user_callouts_helper.rb @@ -1,11 +1,6 @@ module UserCalloutsHelper GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration'.freeze - # Higher value = higher priority - PRIORITY = { - GKE_CLUSTER_INTEGRATION: 0 - }.freeze - def show_gke_cluster_integration_callout?(project) current_user && !user_dismissed?(GKE_CLUSTER_INTEGRATION) && can?(current_user, :create_cluster, project) diff --git a/app/models/user_callout.rb b/app/models/user_callout.rb index 8b31aa6fa5c..a7cfe5df7c0 100644 --- a/app/models/user_callout.rb +++ b/app/models/user_callout.rb @@ -1,6 +1,13 @@ class UserCallout < ActiveRecord::Base belongs_to :user + enum feature_name: { + gke_cluster_integration: 0 + } + validates :user, presence: true - validates :feature_name, presence: true, uniqueness: { scope: :user_id } + validates :feature_name, + presence: true, + uniqueness: { scope: :user_id }, + inclusion: { in: UserCallout.feature_names.keys } end diff --git a/db/migrate/20180125214301_create_user_callouts.rb b/db/migrate/20180125214301_create_user_callouts.rb index 945f4181274..856eff36ae0 100644 --- a/db/migrate/20180125214301_create_user_callouts.rb +++ b/db/migrate/20180125214301_create_user_callouts.rb @@ -7,7 +7,7 @@ class CreateUserCallouts < ActiveRecord::Migration def change create_table :user_callouts do |t| - t.string :feature_name, null: false + t.integer :feature_name, null: false t.references :user, index: true, foreign_key: { on_delete: :cascade }, null: false end diff --git a/db/schema.rb b/db/schema.rb index 6e50b7681d0..14024164359 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1770,7 +1770,7 @@ ActiveRecord::Schema.define(version: 20180202111106) do add_index "user_agent_details", ["subject_id", "subject_type"], name: "index_user_agent_details_on_subject_id_and_subject_type", using: :btree create_table "user_callouts", force: :cascade do |t| - t.string "feature_name", null: false + t.integer "feature_name", null: false t.integer "user_id", null: false end diff --git a/spec/controllers/user_callouts_controller_spec.rb b/spec/controllers/user_callouts_controller_spec.rb index ac295aa72bb..48e2ff75cac 100644 --- a/spec/controllers/user_callouts_controller_spec.rb +++ b/spec/controllers/user_callouts_controller_spec.rb @@ -8,27 +8,41 @@ describe UserCalloutsController do end describe "POST #create" do - subject { post :create, feature_name: 'feature_name', format: :json } + subject { post :create, feature_name: feature_name, format: :json } - context 'when callout entry does not exist' do - it 'should create a callout entry with dismissed state' do - expect { subject }.to change { UserCallout.count }.by(1) + context 'with valid feature name' do + let(:feature_name) { UserCallout.feature_names.keys.first } + + context 'when callout entry does not exist' do + it 'should create a callout entry with dismissed state' do + expect { subject }.to change { UserCallout.count }.by(1) + end + + it 'should return success' do + subject + + expect(response).to have_gitlab_http_status(:ok) + end end - it 'should return success' do - subject + context 'when callout entry already exists' do + let!(:callout) { create(:user_callout, feature_name: UserCallout.feature_names.keys.first, user: user) } + + it 'should return success' do + subject - expect(response).to have_gitlab_http_status(:ok) + expect(response).to have_gitlab_http_status(:ok) + end end end - context 'when callout entry already exists' do - let!(:callout) { create(:user_callout, feature_name: 'feature_name', user: user) } + context 'with invalid feature name' do + let(:feature_name) { 'bogus_feature_name' } - it 'should return success' do + it 'should return bad request' do subject - expect(response).to have_gitlab_http_status(:ok) + expect(response).to have_gitlab_http_status(:bad_request) end end end diff --git a/spec/factories/user_callouts.rb b/spec/factories/user_callouts.rb index ae83d65da2e..528e442c14b 100644 --- a/spec/factories/user_callouts.rb +++ b/spec/factories/user_callouts.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory :user_callout do - feature_name 'test_callout' + feature_name :gke_cluster_integration user end diff --git a/spec/models/user_callout_spec.rb b/spec/models/user_callout_spec.rb index b39d12e48ac..64ba17c81fe 100644 --- a/spec/models/user_callout_spec.rb +++ b/spec/models/user_callout_spec.rb @@ -11,6 +11,6 @@ describe UserCallout do it { is_expected.to validate_presence_of(:user) } it { is_expected.to validate_presence_of(:feature_name) } - it { is_expected.to validate_uniqueness_of(:feature_name).scoped_to(:user_id) } + it { is_expected.to validate_uniqueness_of(:feature_name).scoped_to(:user_id).ignoring_case_sensitivity } end end -- cgit v1.2.1 From c1e1f8070b5f41731bea4dab936690382bfb486e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Mon, 5 Feb 2018 14:26:01 +0100 Subject: Bump UserCallout feature_name enum index --- app/models/user_callout.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/user_callout.rb b/app/models/user_callout.rb index a7cfe5df7c0..e4b69382626 100644 --- a/app/models/user_callout.rb +++ b/app/models/user_callout.rb @@ -2,7 +2,7 @@ class UserCallout < ActiveRecord::Base belongs_to :user enum feature_name: { - gke_cluster_integration: 0 + gke_cluster_integration: 1 } validates :user, presence: true -- cgit v1.2.1 From a85b85e1d8e6a482af7d13477068e6ab976c4b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Mon, 5 Feb 2018 14:33:49 +0100 Subject: Refactor .show_gke_cluster_integration_callout? --- app/helpers/user_callouts_helper.rb | 4 ++-- spec/helpers/user_callouts_helper_spec.rb | 28 ++++++++++------------------ 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/app/helpers/user_callouts_helper.rb b/app/helpers/user_callouts_helper.rb index a292f676331..6368e248c6e 100644 --- a/app/helpers/user_callouts_helper.rb +++ b/app/helpers/user_callouts_helper.rb @@ -2,8 +2,8 @@ module UserCalloutsHelper GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration'.freeze def show_gke_cluster_integration_callout?(project) - current_user && !user_dismissed?(GKE_CLUSTER_INTEGRATION) && - can?(current_user, :create_cluster, project) + can?(current_user, :create_cluster, project) && + !user_dismissed?(GKE_CLUSTER_INTEGRATION) end private diff --git a/spec/helpers/user_callouts_helper_spec.rb b/spec/helpers/user_callouts_helper_spec.rb index 42c2e7827b2..27455705d23 100644 --- a/spec/helpers/user_callouts_helper_spec.rb +++ b/spec/helpers/user_callouts_helper_spec.rb @@ -12,44 +12,36 @@ describe UserCalloutsHelper do subject { helper.show_gke_cluster_integration_callout?(project) } - context 'when user has not dismissed' do + context 'when user can create a cluster' do before do - allow(helper).to receive(:user_dismissed?).and_return(false) + allow(helper).to receive(:can?).with(anything, :create_cluster, anything) + .and_return(true) end - context 'when user can create a cluster' do + context 'when user has not dismissed' do before do - allow(helper).to receive(:can?).with(anything, :create_cluster, anything) - .and_return(true) + allow(helper).to receive(:user_dismissed?).and_return(false) end it { is_expected.to be true } end - context 'when user can not create a cluster' do + context 'when user dismissed' do before do - allow(helper).to receive(:can?).with(anything, :create_cluster, anything) - .and_return(false) + allow(helper).to receive(:user_dismissed?).and_return(true) end it { is_expected.to be false } end end - context 'when user dismissed' do + context 'when user can not create a cluster' do before do - allow(helper).to receive(:user_dismissed?).and_return(true) + allow(helper).to receive(:can?).with(anything, :create_cluster, anything) + .and_return(false) end it { is_expected.to be false } end - - context 'when the user is not logged in' do - before do - allow(helper).to receive(:current_user).and_return(nil) - end - - it { is_expected.to be_falsey } - end end end -- cgit v1.2.1 From 5976410be2ea26ac5aa2e418a32f3105bf29e523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Mon, 5 Feb 2018 14:48:28 +0100 Subject: Refactor UserCalloutsController enum check --- app/controllers/user_callouts_controller.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/controllers/user_callouts_controller.rb b/app/controllers/user_callouts_controller.rb index aa048a9a1fc..18cde4a7b1a 100644 --- a/app/controllers/user_callouts_controller.rb +++ b/app/controllers/user_callouts_controller.rb @@ -1,6 +1,6 @@ class UserCalloutsController < ApplicationController def create - if check_feature_name && ensure_callout + if ensure_callout.persisted? respond_to do |format| format.json { head :ok } end @@ -13,15 +13,11 @@ class UserCalloutsController < ApplicationController private - def check_feature_name - UserCallout.feature_names.keys.include?(callout_param) - end - def ensure_callout - current_user.callouts.find_or_create_by(feature_name: callout_param) + current_user.callouts.find_or_create_by(feature_name: UserCallout.feature_names[feature_name]) end - def callout_param + def feature_name params.require(:feature_name) end end -- cgit v1.2.1 From f24705212791072a93edd4f7b1c530507b6a2c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Mon, 5 Feb 2018 14:49:29 +0100 Subject: Add CHANGELOG --- changelogs/unreleased/persistent-callouts.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/persistent-callouts.yml diff --git a/changelogs/unreleased/persistent-callouts.yml b/changelogs/unreleased/persistent-callouts.yml new file mode 100644 index 00000000000..ca949a3b96c --- /dev/null +++ b/changelogs/unreleased/persistent-callouts.yml @@ -0,0 +1,5 @@ +--- +title: Add backend for persistently dismissably callouts +merge_request: +author: +type: added -- cgit v1.2.1