diff --git a/app/helpers/routing/projects_helper.rb b/app/helpers/routing/projects_helper.rb index 1f00d283a30af6f3093abe482eaf944da335e269..1e2dc3888e5fea400a58651091d0c084239c9ede 100644 --- a/app/helpers/routing/projects_helper.rb +++ b/app/helpers/routing/projects_helper.rb @@ -76,6 +76,10 @@ def release_url(entity, *args) project_release_url(entity.project, entity, *args) end + def project_wiki_page_url(entity, *args) + project_wiki_url(entity.project, entity.canonical_slug, *args) + end + def edit_milestone_path(entity, *args) if entity.resource_parent.is_a?(Group) edit_group_milestone_path(entity.resource_parent, entity, *args) diff --git a/app/models/concerns/noteable.rb b/app/models/concerns/noteable.rb index 77e2a091139d5a70a173ebd3ff8d29beeeaefbc2..736060ad15b567c70002a42037a2ebc1c42ca272 100644 --- a/app/models/concerns/noteable.rb +++ b/app/models/concerns/noteable.rb @@ -12,12 +12,12 @@ module Noteable class_methods do # `Noteable` class names that support replying to individual notes. def replyable_types - %w[Issue MergeRequest AbuseReport] + %w[Issue MergeRequest AbuseReport WikiPage::Meta] end # `Noteable` class names that support resolvable notes. def resolvable_types - %w[Issue MergeRequest DesignManagement::Design AbuseReport] + %w[Issue MergeRequest DesignManagement::Design AbuseReport WikiPage::Meta] end # `Noteable` class names that support creating/forwarding individual notes. diff --git a/app/models/discussion_note.rb b/app/models/discussion_note.rb index 354553bee1a3d14d5146651d00a8983ecbcf31bc..afbaead400b4d809224bfdf651c46679f96d1288 100644 --- a/app/models/discussion_note.rb +++ b/app/models/discussion_note.rb @@ -11,7 +11,7 @@ class DiscussionNote < Note # Names of all implementers of `Noteable` that support discussions. def self.noteable_types - %w[MergeRequest Issue Commit Snippet] + %w[MergeRequest Issue Commit Snippet WikiPage::Meta] end validates :noteable_type, inclusion: { in: noteable_types } diff --git a/app/models/note.rb b/app/models/note.rb index 6c94f04ce329dae0150c6b4019a20662c026aedf..cac566a1297eb49820f5812a56ae7b951a65d5fa 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -361,6 +361,10 @@ def for_personal_snippet? noteable.is_a?(PersonalSnippet) end + def for_wiki_page? + noteable_type == "WikiPage::Meta" + end + def for_project_noteable? !(for_personal_snippet? || for_abuse_report? || group_level_issue?) end diff --git a/app/models/wiki_page/meta.rb b/app/models/wiki_page/meta.rb index e70e5dbe9731526c867107e57ec9de2d9e69caa4..9df4802a2150b4fd84e3c135565ac84f42ad8067 100644 --- a/app/models/wiki_page/meta.rb +++ b/app/models/wiki_page/meta.rb @@ -3,6 +3,8 @@ class WikiPage class Meta < ApplicationRecord include HasWikiPageMetaAttributes + include Mentionable + include Noteable self.table_name = 'wiki_page_meta' @@ -10,15 +12,14 @@ class Meta < ApplicationRecord belongs_to :namespace, optional: true has_many :slugs, class_name: 'WikiPage::Slug', foreign_key: 'wiki_page_meta_id', inverse_of: :wiki_page_meta + has_many :notes, as: :noteable + has_many :user_mentions, class_name: 'Wikis::UserMention', foreign_key: 'wiki_page_meta_id', + inverse_of: :wiki_page_meta validate :project_or_namespace_present? alias_method :resource_parent, :project - def container_key - namespace.present? ? :namespace_id : :project_id - end - def container project || namespace end @@ -28,6 +29,14 @@ def container=(value) self.namespace = value if value.is_a?(Namespace) end + def for_group_wiki? + namespace_id.present? + end + + def container_key + for_group_wiki? ? :namespace_id : :project_id + end + private def project_or_namespace_present? diff --git a/app/models/wikis/user_mention.rb b/app/models/wikis/user_mention.rb new file mode 100644 index 0000000000000000000000000000000000000000..245e4c694c9004d0a2532272aa94e5096b47153d --- /dev/null +++ b/app/models/wikis/user_mention.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Wikis + class UserMention < UserMention + self.table_name = 'wiki_page_meta_user_mentions' + + belongs_to :wiki_page_meta, class_name: 'WikiPage::Meta', optional: false + belongs_to :note, optional: false + + before_validation :set_namespace_id_from_note, on: :create + + private + + def set_namespace_id_from_note + self.namespace_id ||= note&.namespace_id + end + end +end diff --git a/db/docs/wiki_page_meta_user_mentions.yml b/db/docs/wiki_page_meta_user_mentions.yml new file mode 100644 index 0000000000000000000000000000000000000000..4bdeba8b714b4a2e8d35a2921f0de3beca0388f7 --- /dev/null +++ b/db/docs/wiki_page_meta_user_mentions.yml @@ -0,0 +1,12 @@ +--- +table_name: wiki_page_meta_user_mentions +classes: +- Wikis::UserMention +feature_categories: +- wiki +description: User mentions in wiki page notes +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/163305 +milestone: '17.5' +gitlab_schema: gitlab_main_cell +sharding_key: + namespace_id: namespaces diff --git a/db/migrate/20240917054235_create_wiki_page_user_mentions.rb b/db/migrate/20240917054235_create_wiki_page_user_mentions.rb new file mode 100644 index 0000000000000000000000000000000000000000..87348128997654e7e262ad9f8de112a4189c90bf --- /dev/null +++ b/db/migrate/20240917054235_create_wiki_page_user_mentions.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +# See https://docs.gitlab.com/ee/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class CreateWikiPageUserMentions < Gitlab::Database::Migration[2.2] + enable_lock_retries! + + milestone '17.5' + + def up + create_table :wiki_page_meta_user_mentions do |t| # rubocop:disable Migration/EnsureFactoryForTable -- No factory needed + t.bigint :wiki_page_meta_id, null: false + t.bigint :note_id, null: false + t.bigint :namespace_id, null: false + t.bigint :mentioned_users_ids, array: true, default: nil + t.bigint :mentioned_projects_ids, array: true, default: nil + t.bigint :mentioned_groups_ids, array: true, default: nil + + t.index :note_id + t.index :namespace_id + t.index [:wiki_page_meta_id, :note_id], + unique: true, + name: :index_wiki_meta_user_mentions_on_wiki_page_meta_id_and_note_id + end + end + + def down + drop_table :wiki_page_meta_user_mentions, if_exists: true + end +end diff --git a/db/migrate/20240917061401_add_wiki_page_meta_foreign_key_to_wiki_page_meta_user_mentions.rb b/db/migrate/20240917061401_add_wiki_page_meta_foreign_key_to_wiki_page_meta_user_mentions.rb new file mode 100644 index 0000000000000000000000000000000000000000..2d7320b8d38d9ba98eaca9d6a5316c06ee2552f9 --- /dev/null +++ b/db/migrate/20240917061401_add_wiki_page_meta_foreign_key_to_wiki_page_meta_user_mentions.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddWikiPageMetaForeignKeyToWikiPageMetaUserMentions < Gitlab::Database::Migration[2.2] + milestone '17.5' + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :wiki_page_meta_user_mentions, :wiki_page_meta, column: :wiki_page_meta_id, + on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :wiki_page_meta_user_mentions, column: :wiki_page_meta_id + end + end +end diff --git a/db/migrate/20240917061421_add_notes_foreign_key_to_wiki_page_meta_user_mentions.rb b/db/migrate/20240917061421_add_notes_foreign_key_to_wiki_page_meta_user_mentions.rb new file mode 100644 index 0000000000000000000000000000000000000000..5bda015734020da98e7fcaf30657ab25443ebcb1 --- /dev/null +++ b/db/migrate/20240917061421_add_notes_foreign_key_to_wiki_page_meta_user_mentions.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddNotesForeignKeyToWikiPageMetaUserMentions < Gitlab::Database::Migration[2.2] + milestone '17.5' + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :wiki_page_meta_user_mentions, :notes, column: :note_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :wiki_page_meta_user_mentions, column: :note_id + end + end +end diff --git a/db/migrate/20240917110235_add_namespaces_foreign_key_to_wiki_page_meta_user_mentions.rb b/db/migrate/20240917110235_add_namespaces_foreign_key_to_wiki_page_meta_user_mentions.rb new file mode 100644 index 0000000000000000000000000000000000000000..0c5bb9b5edc4ef08b4738a9d06ba48a83d239b03 --- /dev/null +++ b/db/migrate/20240917110235_add_namespaces_foreign_key_to_wiki_page_meta_user_mentions.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddNamespacesForeignKeyToWikiPageMetaUserMentions < Gitlab::Database::Migration[2.2] + milestone '17.5' + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :wiki_page_meta_user_mentions, :namespaces, column: :namespace_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :wiki_page_meta_user_mentions, column: :namespace_id + end + end +end diff --git a/db/schema_migrations/20240917054235 b/db/schema_migrations/20240917054235 new file mode 100644 index 0000000000000000000000000000000000000000..09777105373ce3a04d4863a6bea494f8ce4bf859 --- /dev/null +++ b/db/schema_migrations/20240917054235 @@ -0,0 +1 @@ +9ee63c7a0b13f8eabca033494d551c498d8320144f6acec53b2bd6263e1b5152 \ No newline at end of file diff --git a/db/schema_migrations/20240917061401 b/db/schema_migrations/20240917061401 new file mode 100644 index 0000000000000000000000000000000000000000..2bb675a66fff2a5826f58e614b87d98b394bdfa9 --- /dev/null +++ b/db/schema_migrations/20240917061401 @@ -0,0 +1 @@ +ec9255f62950f75064ad2cd65c9fef6a1b4c136d4bb86238b24ed567098fb28e \ No newline at end of file diff --git a/db/schema_migrations/20240917061421 b/db/schema_migrations/20240917061421 new file mode 100644 index 0000000000000000000000000000000000000000..b2212b66a586d1633569969470eb77dd1efeb401 --- /dev/null +++ b/db/schema_migrations/20240917061421 @@ -0,0 +1 @@ +caa78be456eebea5d9fc8cbcc0d0daa56e11f3e633f5327014702814919a073c \ No newline at end of file diff --git a/db/schema_migrations/20240917110235 b/db/schema_migrations/20240917110235 new file mode 100644 index 0000000000000000000000000000000000000000..63da6a53dc4c7b33561b67e0af15d0f8bee96e89 --- /dev/null +++ b/db/schema_migrations/20240917110235 @@ -0,0 +1 @@ +b844c5179a55387b9c0f631a9172b7b62fae98e38d8c86532dbcac2365f8a1c7 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 1161adad1f296b3198d4b5db7ec4f8a9532259b3..c97e1223e26519ffa0711d4264d4d0eed939540a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -20647,6 +20647,25 @@ CREATE SEQUENCE wiki_page_meta_id_seq ALTER SEQUENCE wiki_page_meta_id_seq OWNED BY wiki_page_meta.id; +CREATE TABLE wiki_page_meta_user_mentions ( + id bigint NOT NULL, + wiki_page_meta_id bigint NOT NULL, + note_id bigint NOT NULL, + namespace_id bigint NOT NULL, + mentioned_users_ids bigint[], + mentioned_projects_ids bigint[], + mentioned_groups_ids bigint[] +); + +CREATE SEQUENCE wiki_page_meta_user_mentions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE wiki_page_meta_user_mentions_id_seq OWNED BY wiki_page_meta_user_mentions.id; + CREATE TABLE wiki_page_slugs ( id bigint NOT NULL, canonical boolean DEFAULT false NOT NULL, @@ -22812,6 +22831,8 @@ ALTER TABLE ONLY webauthn_registrations ALTER COLUMN id SET DEFAULT nextval('web ALTER TABLE ONLY wiki_page_meta ALTER COLUMN id SET DEFAULT nextval('wiki_page_meta_id_seq'::regclass); +ALTER TABLE ONLY wiki_page_meta_user_mentions ALTER COLUMN id SET DEFAULT nextval('wiki_page_meta_user_mentions_id_seq'::regclass); + ALTER TABLE ONLY wiki_page_slugs ALTER COLUMN id SET DEFAULT nextval('wiki_page_slugs_id_seq'::regclass); ALTER TABLE ONLY wiki_repository_states ALTER COLUMN id SET DEFAULT nextval('wiki_repository_states_id_seq'::regclass); @@ -25622,6 +25643,9 @@ ALTER TABLE ONLY webauthn_registrations ALTER TABLE ONLY wiki_page_meta ADD CONSTRAINT wiki_page_meta_pkey PRIMARY KEY (id); +ALTER TABLE ONLY wiki_page_meta_user_mentions + ADD CONSTRAINT wiki_page_meta_user_mentions_pkey PRIMARY KEY (id); + ALTER TABLE ONLY wiki_page_slugs ADD CONSTRAINT wiki_page_slugs_pkey PRIMARY KEY (id); @@ -31239,10 +31263,16 @@ CREATE UNIQUE INDEX index_webauthn_registrations_on_credential_xid ON webauthn_r CREATE INDEX index_webauthn_registrations_on_user_id ON webauthn_registrations USING btree (user_id); +CREATE UNIQUE INDEX index_wiki_meta_user_mentions_on_wiki_page_meta_id_and_note_id ON wiki_page_meta_user_mentions USING btree (wiki_page_meta_id, note_id); + CREATE INDEX index_wiki_page_meta_on_namespace_id ON wiki_page_meta USING btree (namespace_id); CREATE INDEX index_wiki_page_meta_on_project_id ON wiki_page_meta USING btree (project_id); +CREATE INDEX index_wiki_page_meta_user_mentions_on_namespace_id ON wiki_page_meta_user_mentions USING btree (namespace_id); + +CREATE INDEX index_wiki_page_meta_user_mentions_on_note_id ON wiki_page_meta_user_mentions USING btree (note_id); + CREATE INDEX index_wiki_page_slugs_on_project_id ON wiki_page_slugs USING btree (project_id); CREATE UNIQUE INDEX index_wiki_page_slugs_on_slug_and_wiki_page_meta_id ON wiki_page_slugs USING btree (slug, wiki_page_meta_id); @@ -34208,6 +34238,9 @@ ALTER TABLE ONLY users ALTER TABLE ONLY analytics_devops_adoption_snapshots ADD CONSTRAINT fk_78c9eac821 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE; +ALTER TABLE ONLY wiki_page_meta_user_mentions + ADD CONSTRAINT fk_7954f34107 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE; + ALTER TABLE ONLY topics ADD CONSTRAINT fk_79ae18bd4b FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE; @@ -34601,12 +34634,18 @@ ALTER TABLE ONLY uploads ALTER TABLE ONLY deployments ADD CONSTRAINT fk_b9a3851b82 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; +ALTER TABLE ONLY wiki_page_meta_user_mentions + ADD CONSTRAINT fk_ba8a9d7f95 FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE; + ALTER TABLE ONLY project_compliance_standards_adherence ADD CONSTRAINT fk_baf6f6f878 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; ALTER TABLE p_ci_runner_machine_builds ADD CONSTRAINT fk_bb490f12fe_p FOREIGN KEY (partition_id, build_id) REFERENCES p_ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE; +ALTER TABLE ONLY wiki_page_meta_user_mentions + ADD CONSTRAINT fk_bc155eba89 FOREIGN KEY (wiki_page_meta_id) REFERENCES wiki_page_meta(id) ON DELETE CASCADE; + ALTER TABLE ONLY security_orchestration_policy_rule_schedules ADD CONSTRAINT fk_bcbb90477f FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; diff --git a/ee/app/models/ee/note.rb b/ee/app/models/ee/note.rb index abcb8a998d35ce42143362c000d201f738cb5a9c..905bc2e6486680104078feb0538a3c41340f23e8 100644 --- a/ee/app/models/ee/note.rb +++ b/ee/app/models/ee/note.rb @@ -51,13 +51,17 @@ def for_epic? noteable.is_a?(Epic) end + def for_group_wiki? + for_wiki_page? && noteable&.for_group_wiki? + end + def for_vulnerability? noteable.is_a?(Vulnerability) end override :for_project_noteable? def for_project_noteable? - !for_epic? && super + !(for_epic? || for_group_wiki?) && super end override :banzai_render_context diff --git a/ee/spec/factories/notes.rb b/ee/spec/factories/notes.rb index 46105632fb833fb950837b28607b0119fa07c69c..832f6c987e03b5102810623a8694fdeed23ed708 100644 --- a/ee/spec/factories/notes.rb +++ b/ee/spec/factories/notes.rb @@ -10,6 +10,12 @@ trait :on_vulnerability do noteable { association(:vulnerability, project: project) } end + + trait :on_group_level_wiki do + project { nil } + namespace { association :group } + noteable { association(:wiki_page_meta, namespace: namespace) } + end end end diff --git a/ee/spec/models/note_spec.rb b/ee/spec/models/note_spec.rb index 2b6d05affd2555182d5af88b7d3a9daea999eff6..df3e54b26f3b30d42b49cc082a66936d8050911a 100644 --- a/ee/spec/models/note_spec.rb +++ b/ee/spec/models/note_spec.rb @@ -297,6 +297,16 @@ end end + describe '#for_group_wiki?' do + it 'returns true for a group-level wiki page' do + expect(build_stubbed(:note_on_wiki_page, :on_group_level_wiki).for_group_wiki?).to be_truthy + end + + it 'returns false for a project-level wiki page' do + expect(build_stubbed(:note_on_wiki_page, :on_project_level_wiki).for_group_wiki?).to be_falsy + end + end + describe '.note_starting_with' do it 'returns a note matching the prefix' do create(:note) diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb index 3f9ba7c5db41d39f01269fcf687f9c29cac2ff91..1bc61f806b59c2b1cd51b69e8f58e37e216fde42 100644 --- a/lib/gitlab/url_builder.rb +++ b/lib/gitlab/url_builder.rb @@ -101,6 +101,8 @@ def note_url(note, **options) instance.gitlab_snippet_url(note.noteable, anchor: dom_id(note), **options) elsif note.for_abuse_report? instance.admin_abuse_report_url(note.noteable, anchor: dom_id(note), **options) + elsif note.for_wiki_page? + instance.project_wiki_page_url(note.noteable, anchor: dom_id(note), **options) end end diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb index 824ddfa7ece807bc2f6d2384217fb0c3399431b9..c99dc35d577e83e8b749461317320c4da314ccfa 100644 --- a/spec/factories/notes.rb +++ b/spec/factories/notes.rb @@ -18,6 +18,7 @@ factory :note_on_personal_snippet, traits: [:on_personal_snippet] factory :note_on_design, traits: [:on_design] factory :note_on_alert, traits: [:on_alert] + factory :note_on_wiki_page, traits: [:on_wiki_page] factory :system_note, traits: [:system] factory :discussion_note, class: 'DiscussionNote' @@ -39,6 +40,8 @@ factory :discussion_note_on_project_snippet, traits: [:on_project_snippet], class: 'DiscussionNote' + factory :discussion_note_on_wiki_page, traits: [:on_wiki_page], class: 'DiscussionNote' + factory :legacy_diff_note_on_commit, traits: [:on_commit, :legacy_diff_note], class: 'LegacyDiffNote' factory :legacy_diff_note_on_merge_request, traits: [:on_merge_request, :legacy_diff_note], class: 'LegacyDiffNote' do @@ -140,6 +143,10 @@ noteable { association(:work_item, :group_level) } end + trait :on_project_level_wiki do + noteable { association(:wiki_page_meta, project: project) } + end + trait :on_merge_request do noteable { association(:merge_request, source_project: project) } end @@ -171,6 +178,10 @@ noteable { association(:alert_management_alert, project: project) } end + trait :on_wiki_page do + noteable { association(:wiki_page_meta, project: project) } + end + trait :resolved do resolved_at { Time.now } resolved_by { association(:user) } diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb index f33826058abdf165ce3ff282cbbaaaf83f87b8ad..889b5199c0dc33159dddc23fae34a350d7d84954 100644 --- a/spec/lib/gitlab/url_builder_spec.rb +++ b/spec/lib/gitlab/url_builder_spec.rb @@ -80,6 +80,22 @@ end end + context 'when passing a wiki note' do + let_it_be(:wiki_page_slug) { create(:wiki_page_slug, canonical: true) } + let(:wiki_page_meta) { wiki_page_slug.reload.wiki_page_meta } + let(:note) { build_stubbed(:note, noteable: wiki_page_meta, project: wiki_page_meta.project) } + + let(:path) { "/#{note.project.full_path}/-/wikis/#{note.noteable.canonical_slug}#note_#{note.id}" } + + it 'returns the full URL' do + expect(subject.build(note)).to eq("#{Gitlab.config.gitlab.url}#{path}") + end + + it 'returns only the path if only_path is given' do + expect(subject.build(note, only_path: true)).to eq(path) + end + end + context 'when passing a compare' do # NOTE: The Compare requires an actual repository, which isn't available # with the `build_stubbed` strategy used by the table tests above diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index cc0bf75e6bae78819ec1077d5332e3e955a88a4f..da457df2cc3a911f1e251e593c07e0c6a6c246dd 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -105,6 +105,14 @@ end end + context 'when noteable is a wiki page' do + subject { build(:note, noteable: build_stubbed(:wiki_page_meta), project: nil, namespace: nil) } + + it 'is not valid without project or namespace' do + is_expected.to be_invalid + end + end + describe 'max notes limit' do let_it_be(:noteable) { create(:issue) } let_it_be(:existing_note) { create(:note, project: noteable.project, noteable: noteable) } @@ -1396,6 +1404,12 @@ def retrieve_participants end end + describe '#for_wiki_page?' do + it 'returns true for a wiki_page' do + expect(build(:note_on_wiki_page).for_wiki_page?).to be_truthy + end + end + describe '#for_design' do it 'is true when the noteable is a design' do note = build(:note, noteable: build(:design)) diff --git a/spec/models/wiki_page/meta_spec.rb b/spec/models/wiki_page/meta_spec.rb index 523baf967eb3aaeea47be7cf70df1ca6503472d3..b84246b95738107a0085355c292f3fc70e4ff945 100644 --- a/spec/models/wiki_page/meta_spec.rb +++ b/spec/models/wiki_page/meta_spec.rb @@ -10,6 +10,15 @@ it { is_expected.to belong_to(:project) } it { is_expected.to have_many(:slugs) } it { is_expected.to have_many(:events) } + it { is_expected.to have_many(:notes) } + + it do + is_expected + .to have_many(:user_mentions) + .class_name('Wikis::UserMention') + .with_foreign_key('wiki_page_meta_id') + .inverse_of('wiki_page_meta') + end it 'can find slugs' do meta = create(:wiki_page_meta) diff --git a/spec/models/wikis/user_mention_spec.rb b/spec/models/wikis/user_mention_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..f17147ac73b4413c05236e34cdc3543bf89343df --- /dev/null +++ b/spec/models/wikis/user_mention_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Wikis::UserMention, feature_category: :wiki do + describe 'associations' do + it { is_expected.to belong_to(:wiki_page_meta).optional(false) } + it { is_expected.to belong_to(:note).optional(false) } + end + + it_behaves_like 'has user mentions' +end