Module: Mentionable

Extended by:
ActiveSupport::Concern
Included in:
Commit, Issuable, Note
Defined in:
app/models/concerns/mentionable.rb

Overview

Mentionable concern

Contains functionality related to objects that can mention Users, Issues, MergeRequests, or Commits by GFM references.

Used by Issue, Note, MergeRequest, and Commit.

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Instance Method Details

#all_references(current_user = self.author, text = nil) ⇒ Object


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'app/models/concerns/mentionable.rb', line 46

def all_references(current_user = self.author, text = nil)
  ext = Gitlab::ReferenceExtractor.new(self.project, current_user, self.author)

  if text
    ext.analyze(text)
  else
    self.class.mentionable_attrs.each do |attr, options|
      text = send(attr)

      context = options.dup
      context[:cache_key] = [self, attr] if context.delete(:cache) && self.persisted?

      ext.analyze(text, context)
    end
  end

  ext
end

#create_cross_references!(author = self.author, without = [], text = nil) ⇒ Object

Create a cross-reference Note for each GFM reference to another Mentionable found in the mentionable_attrs.


81
82
83
84
85
86
87
88
89
90
91
92
# File 'app/models/concerns/mentionable.rb', line 81

def create_cross_references!(author = self.author, without = [], text = nil)
  refs = referenced_mentionables(author, text)

  # We're using this method instead of Array diffing because that requires
  # both of the object's `hash` values to be the same, which may not be the
  # case for otherwise identical Commit objects.
  refs.reject! { |ref| without.include?(ref) || cross_reference_exists?(ref) }

  refs.each do |ref|
    SystemNoteService.cross_reference(ref, local_reference, author)
  end
end

#create_new_cross_references!(author = self.author) ⇒ Object

When a mentionable field is changed, creates cross-reference notes that don't already exist


96
97
98
99
100
101
102
103
104
105
# File 'app/models/concerns/mentionable.rb', line 96

def create_new_cross_references!(author = self.author)
  changes = detect_mentionable_changes

  return if changes.empty?

  original_text = changes.collect { |_, vals| vals.first }.join(' ')

  preexisting = referenced_mentionables(author, original_text)
  create_cross_references!(author, preexisting)
end

#gfm_reference(from_project = nil) ⇒ Object

Returns the text used as the body of a Note when this object is referenced

By default this will be the class name and the result of calling `to_reference` on the object.


34
35
36
37
38
39
# File 'app/models/concerns/mentionable.rb', line 34

def gfm_reference(from_project = nil)
  # "MergeRequest" > "merge_request" > "Merge request" > "merge request"
  friendly_name = self.class.to_s.underscore.humanize.downcase

  "#{friendly_name} #{to_reference(from_project)}"
end

#local_referenceObject

The GFM reference to this Mentionable, which shouldn't be included in its #references.


42
43
44
# File 'app/models/concerns/mentionable.rb', line 42

def local_reference
  self
end

#mentioned_users(current_user = nil) ⇒ Object


65
66
67
# File 'app/models/concerns/mentionable.rb', line 65

def mentioned_users(current_user = nil)
  all_references(current_user).users
end

#referenced_mentionables(current_user = self.author, text = nil) ⇒ Object

Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.


70
71
72
73
74
75
76
77
78
# File 'app/models/concerns/mentionable.rb', line 70

def referenced_mentionables(current_user = self.author, text = nil)
  refs = all_references(current_user, text)
  refs = (refs.issues + refs.merge_requests + refs.commits)

  # We're using this method instead of Array diffing because that requires
  # both of the object's `hash` values to be the same, which may not be the
  # case for otherwise identical Commit objects.
  refs.reject { |ref| ref == local_reference }
end