From bf708e55c2e6035b64861a1cda8bfe3d3b4a2105 Mon Sep 17 00:00:00 2001
From: Jarka Kadlecova <jarka@gitlab.com>
Date: Wed, 18 Jan 2017 18:37:55 -0500
Subject: [PATCH] make mentions working when project not specified

---
 app/models/concerns/cache_markdown_field.rb   |  5 ++++-
 app/models/concerns/mentionable.rb            |  6 +++++-
 lib/banzai/filter/reference_filter.rb         |  4 ++++
 lib/banzai/filter/user_reference_filter.rb    |  5 ++---
 lib/banzai/renderer.rb                        |  4 ++--
 .../filter/user_reference_filter_spec.rb      | 21 +++++++++++++++++++
 spec/models/concerns/mentionable_spec.rb      | 13 +++++++++++-
 spec/models/note_spec.rb                      |  2 ++
 spec/services/notification_service_spec.rb    |  4 ++--
 9 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/app/models/concerns/cache_markdown_field.rb b/app/models/concerns/cache_markdown_field.rb
index 90bd6490a02..25970158e70 100644
--- a/app/models/concerns/cache_markdown_field.rb
+++ b/app/models/concerns/cache_markdown_field.rb
@@ -112,7 +112,10 @@ module CacheMarkdownField
       invalidation_method = "#{html_field}_invalidated?".to_sym
 
       define_method(cache_method) do
-        html = Banzai::Renderer.cacheless_render_field(self, markdown_field)
+        options = {
+          skip_project_check: is_a?(Note) && for_personal_snippet?
+        }
+        html = Banzai::Renderer.cacheless_render_field(self, markdown_field, options)
         __send__("#{html_field}=", html)
         true
       end
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index 8ab0401d288..9ded015aad3 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -49,7 +49,11 @@ module Mentionable
 
     self.class.mentionable_attrs.each do |attr, options|
       text    = __send__(attr)
-      options = options.merge(cache_key: [self, attr], author: author)
+      options = options.merge(
+        cache_key: [self, attr],
+        author: author,
+        skip_project_check: is_a?(Note) && for_personal_snippet?
+      )
 
       extractor.analyze(text, options)
     end
diff --git a/lib/banzai/filter/reference_filter.rb b/lib/banzai/filter/reference_filter.rb
index ab7af1cad21..6640168bfa2 100644
--- a/lib/banzai/filter/reference_filter.rb
+++ b/lib/banzai/filter/reference_filter.rb
@@ -53,6 +53,10 @@ module Banzai
         context[:project]
       end
 
+      def skip_project_check?
+        context[:skip_project_check]
+      end
+
       def reference_class(type)
         "gfm gfm-#{type} has-tooltip"
       end
diff --git a/lib/banzai/filter/user_reference_filter.rb b/lib/banzai/filter/user_reference_filter.rb
index f842b1fb779..8173f888062 100644
--- a/lib/banzai/filter/user_reference_filter.rb
+++ b/lib/banzai/filter/user_reference_filter.rb
@@ -24,11 +24,10 @@ module Banzai
       end
 
       def call
-        return doc if project.nil?
+        return doc if project.nil? && !skip_project_check?
 
         ref_pattern = User.reference_pattern
         ref_pattern_start = /\A#{ref_pattern}\z/
-
         nodes.each do |node|
           if text_node?(node)
             replace_text_when_pattern_matches(node, ref_pattern) do |content|
@@ -58,7 +57,7 @@ module Banzai
       # have `gfm` and `gfm-project_member` class names attached for styling.
       def user_link_filter(text, link_content: nil)
         self.class.references_in(text) do |match, username|
-          if username == 'all'
+          if username == 'all' && !skip_project_check?
             link_to_all(link_content: link_content)
           elsif namespace = namespaces[username]
             link_to_namespace(namespace, link_content: link_content) || match
diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb
index f31fb6c3f71..74663556cbb 100644
--- a/lib/banzai/renderer.rb
+++ b/lib/banzai/renderer.rb
@@ -52,9 +52,9 @@ module Banzai
     end
 
     # Same as +render_field+, but without consulting or updating the cache field
-    def cacheless_render_field(object, field)
+    def cacheless_render_field(object, field, options = {})
       text = object.__send__(field)
-      context = object.banzai_render_context(field)
+      context = object.banzai_render_context(field).merge(options)
 
       cacheless_render(text, context)
     end
diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb
index 5bfeb82e738..2166350f579 100644
--- a/spec/lib/banzai/filter/user_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb
@@ -152,6 +152,27 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
     end
   end
 
+  context 'when a project is not specified' do
+    let(:project) { nil }
+
+    it 'does not link a User' do
+      doc = reference_filter("Hey #{reference}")
+      expect(doc).not_to include('a')
+    end
+
+    context 'when skip_project_check set to true' do
+      it 'links to a User' do
+        doc = reference_filter("Hey #{reference}", skip_project_check: true)
+        expect(doc.css('a').first.attr('href')).to eq urls.user_url(user)
+      end
+
+      it 'does not link users using @all reference' do
+        doc = reference_filter("Hey #{User.reference_prefix}all", skip_project_check: true)
+        expect(doc).not_to include('a')
+      end
+    end
+  end
+
   describe '#namespaces' do
     it 'returns a Hash containing all Namespaces' do
       document = Nokogiri::HTML.fragment("<p>#{user.to_reference}</p>")
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index 8321e0b89f8..63eb7473c97 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -30,12 +30,23 @@ describe Issue, "Mentionable" do
   describe '#mentioned_users' do
     let!(:user) { create(:user, username: 'stranger') }
     let!(:user2) { create(:user, username: 'john') }
-    let!(:issue) { create(:issue, description: "#{user.to_reference} mentioned") }
+    let!(:user3) { create(:user, username: 'jim') }
+    let(:issue) { create(:issue, description: "#{user.to_reference} mentioned") }
 
     subject { issue.mentioned_users }
 
     it { is_expected.to include(user) }
     it { is_expected.not_to include(user2) }
+
+    context 'when a note on personal snippet' do
+      let!(:note) { create(:note_on_personal_snippet, note: "#{user.to_reference} mentioned #{user3.to_reference}") }
+
+      subject { note.mentioned_users }
+
+      it { is_expected.to include(user) }
+      it { is_expected.to include(user3) }
+      it { is_expected.not_to include(user2) }
+    end
   end
 
   describe '#referenced_mentionables' do
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index ddd62d7f0e6..8017bf7a13c 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -152,6 +152,7 @@ describe Note, models: true do
         with([{
           text: note1.note,
           context: {
+            skip_project_check: false,
             pipeline: :note,
             cache_key: [note1, "note"],
             project: note1.project,
@@ -163,6 +164,7 @@ describe Note, models: true do
         with([{
           text: note2.note,
           context: {
+            skip_project_check: false,
             pipeline: :note,
             cache_key: [note2, "note"],
             project: note2.project,
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 0ba210fdc5b..bfbee7ca35f 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -306,8 +306,8 @@ describe NotificationService, services: true do
           should_email(@u_watcher)
           should_email(@u_snippet_author)
 
-          # TODO: make mentions working for pesronal snippets
-          # should_email(@u_mentioned_level)
+          # it emails mentioned users
+          should_email(@u_mentioned)
 
           # it does not email participants with mention notification level
           should_not_email(@u_mentioned_level)
-- 
GitLab