diff --git a/app/models/integration.rb b/app/models/integration.rb index 29d96650a813becdc7c9706e34f42348c5fa3f8a..8007c41683f2aecf6ec3c5219cbd04889dfcac12 100644 --- a/app/models/integration.rb +++ b/app/models/integration.rb @@ -74,6 +74,10 @@ class Integration < ApplicationRecord validate :validate_belongs_to_project_or_group scope :external_issue_trackers, -> { where(category: 'issue_tracker').active } + scope :third_party_wikis, -> { where(type: %w[ConfluenceService ShimoService]).active } + # TODO: Will be modified in 14.7 + # Details: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74501#note_744393645 + # scope :third_party_wikis, -> { where(category: 'third_party_wiki').active } scope :external_wikis, -> { where(type: 'ExternalWikiService').active } scope :active, -> { where(active: true) } scope :by_type, -> (type) { where(type: type) } diff --git a/app/models/integrations/base_third_party_wiki.rb b/app/models/integrations/base_third_party_wiki.rb new file mode 100644 index 0000000000000000000000000000000000000000..67d516c6b58005f00670f96d57cddd1e8cd6f5ae --- /dev/null +++ b/app/models/integrations/base_third_party_wiki.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Integrations + class BaseThirdPartyWiki < Integration + default_value_for :category, 'third_party_wiki' + + validate :only_one_third_party_wiki, if: :activated?, on: :manual_change + + after_commit :cache_project_has_integration + + def self.supported_events + %w() + end + + private + + def only_one_third_party_wiki + return unless project_level? + + if project.integrations.third_party_wikis.where.not(id: id).any? + errors.add(:base, _('Another third-party wiki is already in use. Only one third-party wiki service can be active at a time')) + end + end + + def cache_project_has_integration + return unless project && !project.destroyed? + + project.project_setting.save! unless project.project_setting.persisted? + project.project_setting.update_column(project_settings_cache_key, active?) + end + + def project_settings_cache_key + "has_#{self.class.name.demodulize.underscore}" + end + end +end diff --git a/app/models/integrations/confluence.rb b/app/models/integrations/confluence.rb index 7f111f482dddba46170ce9a3cfff2d9e6008b227..d843878565ea0607f2a2f85a81ee4553e6b33648 100644 --- a/app/models/integrations/confluence.rb +++ b/app/models/integrations/confluence.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Integrations - class Confluence < Integration + class Confluence < BaseThirdPartyWiki include ActionView::Helpers::UrlHelper VALID_SCHEME_MATCH = %r{\Ahttps?\Z}.freeze @@ -13,16 +13,10 @@ class Confluence < Integration validates :confluence_url, presence: true, if: :activated? validate :validate_confluence_url_is_cloud, if: :activated? - after_commit :cache_project_has_confluence - def self.to_param 'confluence' end - def self.supported_events - %w() - end - def title s_('ConfluenceService|Confluence Workspace') end @@ -82,12 +76,5 @@ def confluence_uri_valid? rescue URI::InvalidURIError false end - - def cache_project_has_confluence - return unless project && !project.destroyed? - - project.project_setting.save! unless project.project_setting.persisted? - project.project_setting.update_column(:has_confluence, active?) - end end end diff --git a/app/models/integrations/shimo.rb b/app/models/integrations/shimo.rb index 0e1023bb7a7b8030082e381369ee60734ee90843..dd25a0bc558ac5ce83f17a678c679ab06104c9f3 100644 --- a/app/models/integrations/shimo.rb +++ b/app/models/integrations/shimo.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true module Integrations - class Shimo < Integration + class Shimo < BaseThirdPartyWiki prop_accessor :external_wiki_url validates :external_wiki_url, presence: true, public_url: true, if: :activated? - after_commit :cache_project_has_shimo - def render? return false unless Feature.enabled?(:shimo_integration, project) @@ -33,10 +31,6 @@ def execute(_data) nil end - def self.supported_events - %w() - end - def fields [ { @@ -47,14 +41,5 @@ def fields } ] end - - private - - def cache_project_has_shimo - return unless project && !project.destroyed? - - project.project_setting.save! unless project.project_setting.persisted? - project.project_setting.update_column(:has_shimo, activated?) - end end end diff --git a/db/post_migrate/20211129073034_update_shimo_service_category.rb b/db/post_migrate/20211129073034_update_shimo_service_category.rb new file mode 100644 index 0000000000000000000000000000000000000000..cc241c5b841f6d66aab701eaffdff69718a70d4e --- /dev/null +++ b/db/post_migrate/20211129073034_update_shimo_service_category.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class UpdateShimoServiceCategory < Gitlab::Database::Migration[1.0] + disable_ddl_transaction! + def up + Integrations::Shimo.update_all(category: 'third_party_wiki') + end + + def down + Integrations::Shimo.update_all(category: 'common') + end +end diff --git a/db/post_migrate/20211129073035_update_confluence_service_category.rb b/db/post_migrate/20211129073035_update_confluence_service_category.rb new file mode 100644 index 0000000000000000000000000000000000000000..3d8420732bd0182de3e9dab035408cc725ab9dcf --- /dev/null +++ b/db/post_migrate/20211129073035_update_confluence_service_category.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class UpdateConfluenceServiceCategory < Gitlab::Database::Migration[1.0] + disable_ddl_transaction! + def up + Integrations::Confluence.update_all(category: 'third_party_wiki') + end + + def down + Integrations::Confluence.update_all(category: 'common') + end +end diff --git a/db/schema_migrations/20211129073034 b/db/schema_migrations/20211129073034 new file mode 100644 index 0000000000000000000000000000000000000000..38f9e68191ca1802fba3c670d989ead887ebb1c7 --- /dev/null +++ b/db/schema_migrations/20211129073034 @@ -0,0 +1 @@ +8d1cdf689dc422a435978d359680c2d2a684f73ad588c5c4388f01782fba17d1 \ No newline at end of file diff --git a/db/schema_migrations/20211129073035 b/db/schema_migrations/20211129073035 new file mode 100644 index 0000000000000000000000000000000000000000..1535a69f0dd7c4d1ba43978cf932bc0e8c81d699 --- /dev/null +++ b/db/schema_migrations/20211129073035 @@ -0,0 +1 @@ +4863f144eedf72c9b42e49f3b9a3dd07f01e783afade9538187658a7f632d58f \ No newline at end of file diff --git a/lib/sidebars/projects/panel.rb b/lib/sidebars/projects/panel.rb index 6bb4fb52e2ad6955278adf255aae0c065c33fbed..ee982d4eff26ddb982e48aa81888955350755857 100644 --- a/lib/sidebars/projects/panel.rb +++ b/lib/sidebars/projects/panel.rb @@ -46,15 +46,17 @@ def add_invite_members_menu end def add_wiki_menus - add_menu((third_party_wiki_menu || Sidebars::Projects::Menus::WikiMenu).new(context)) + third_party_wiki_menus.each { |menu| add_menu(menu.new(context)) } add_menu(Sidebars::Projects::Menus::ExternalWikiMenu.new(context)) end - def third_party_wiki_menu + def third_party_wiki_menus wiki_menu_list = [::Sidebars::Projects::Menus::ConfluenceMenu] wiki_menu_list << ::Sidebars::Projects::Menus::ShimoMenu if Feature.enabled?(:shimo_integration, context.project) - wiki_menu_list.find { |wiki_menu| wiki_menu.new(context).render? } + wiki_menu_list.filter do |wiki_menu| + wiki_menu.new(context).render? + end.presence || [Sidebars::Projects::Menus::WikiMenu] end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 74049e27dacb17ce307bc3b2c3b7f1c5c567e6ee..7326acd9c91b246ee04072d567a2c0c601399b1c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -4003,6 +4003,9 @@ msgstr "" msgid "Another issue tracker is already in use. Only one issue tracker service can be active at a time" msgstr "" +msgid "Another third-party wiki is already in use. Only one third-party wiki service can be active at a time" +msgstr "" + msgid "Anti-spam verification" msgstr "" diff --git a/spec/models/integrations/base_third_party_wiki_spec.rb b/spec/models/integrations/base_third_party_wiki_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..1511185df50a025456430df7c9e736cc3397cd3a --- /dev/null +++ b/spec/models/integrations/base_third_party_wiki_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Integrations::BaseThirdPartyWiki do + describe 'Validations' do + let_it_be_with_reload(:project) { create(:project) } + + describe 'only one third party wiki per project' do + subject(:integration) { create(:shimo_integration, project: project, active: true) } + + before do + create(:confluence_integration, project: project, active: true) + end + + context 'when integration is changed manually by user' do + it 'executes the validation' do + valid = integration.valid?(:manual_change) + + expect(valid).to be_falsey + expect(integration.errors[:base]).to include( + _('Another third-party wiki is already in use. Only one third-party wiki service can be active at a time') + ) + end + end + + context 'when integration is changed internally' do + it 'does not execute the validation' do + expect(integration.valid?).to be_truthy + end + end + end + end +end