Module: Mentionable
- Extended by:
- ActiveSupport::Concern
- Included in:
- AbuseReport, AlertManagement::Alert, AntiAbuse::Reports::Note, Commit, DesignManagement::Design, Issuable, Note, Review, Snippet, WikiPage::Meta
- Defined in:
- app/models/concerns/mentionable.rb,
app/models/concerns/mentionable/reference_regexes.rb
Overview
Mentionable concern
Contains functionality related to objects that can mention Users, Issues, MergeRequests, Commits or Snippets by GFM references.
Used by Issue, Note, MergeRequest, and Commit.
Defined Under Namespace
Modules: ReferenceRegexes
Instance Method Summary collapse
- #all_references(current_user = nil, extractor: nil) ⇒ Object
-
#create_cross_references!(author = self.author, without = []) ⇒ Object
Create a cross-reference Note for each GFM reference to another Mentionable found in the
mentionable_attrs
. -
#create_new_cross_references!(author = self.author) ⇒ Object
When a mentionable field is changed, creates cross-reference notes that don’t already exist.
- #directly_addressed_users(current_user = nil) ⇒ Object
- #extractors ⇒ Object
-
#gfm_reference(from = nil) ⇒ Object
Returns the text used as the body of a Note when this object is referenced.
-
#local_reference ⇒ Object
The GFM reference to this Mentionable, which shouldn’t be included in its #references.
-
#matches_cross_reference_regex? ⇒ Boolean
Uses regex to quickly determine if mentionables might be referenced Allows heavy processing to be skipped.
- #mentioned_users(current_user = nil) ⇒ Object
- #referenced_group_users(current_user = nil) ⇒ Object
- #referenced_groups(current_user = nil) ⇒ Object
-
#referenced_mentionables(current_user = self.author) ⇒ Object
Extract GFM references to other Mentionables from this Mentionable.
- #referenced_project_users(current_user = nil) ⇒ Object
- #referenced_projects(current_user = nil) ⇒ Object
- #referenced_users ⇒ Object
- #user_mention_class ⇒ Object
-
#user_mention_identifier ⇒ Object
Identifier for the user mention that is parsed from model description rather then its related notes.
Instance Method Details
#all_references(current_user = nil, extractor: nil) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'app/models/concerns/mentionable.rb', line 48 def all_references(current_user = nil, extractor: nil) # Use custom extractor if it's passed in the function parameters. if extractor extractors[current_user] = extractor else extractor = extractors[current_user] ||= Gitlab::ReferenceExtractor.new(project, current_user) extractor.reset_memoized_values end self.class.mentionable_attrs.each do |attr, | text = __send__(attr) # rubocop:disable GitlabSecurity/PublicSend = .merge( cache_key: [self, attr], author: , skip_project_check: skip_project_check? ).merge(mentionable_params) cached_html = self.try(:updated_cached_html_for, attr.to_sym) [:rendered] = cached_html if cached_html extractor.analyze(text, ) end extractor end |
#create_cross_references!(author = self.author, without = []) ⇒ Object
Create a cross-reference Note for each GFM reference to another Mentionable found in the mentionable_attrs
.
141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'app/models/concerns/mentionable.rb', line 141 def create_cross_references!( = self., without = []) refs = referenced_mentionables() # 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, ) 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
156 157 158 159 160 161 162 |
# File 'app/models/concerns/mentionable.rb', line 156 def create_new_cross_references!( = self.) changes = detect_mentionable_changes return if changes.empty? create_cross_references!() end |
#directly_addressed_users(current_user = nil) ⇒ Object
110 111 112 |
# File 'app/models/concerns/mentionable.rb', line 110 def directly_addressed_users(current_user = nil) all_references(current_user).directly_addressed_users end |
#extractors ⇒ Object
75 76 77 |
# File 'app/models/concerns/mentionable.rb', line 75 def extractors @extractors ||= {} end |
#gfm_reference(from = 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.
36 37 38 39 40 41 |
# File 'app/models/concerns/mentionable.rb', line 36 def gfm_reference(from = nil) # "MergeRequest" > "merge_request" > "Merge request" > "merge request" friendly_name = self.class.to_s.underscore.humanize.downcase "#{friendly_name} #{to_reference(from)}" end |
#local_reference ⇒ Object
The GFM reference to this Mentionable, which shouldn’t be included in its #references.
44 45 46 |
# File 'app/models/concerns/mentionable.rb', line 44 def local_reference self end |
#matches_cross_reference_regex? ⇒ Boolean
Uses regex to quickly determine if mentionables might be referenced Allows heavy processing to be skipped
128 129 130 131 132 133 134 135 136 137 138 |
# File 'app/models/concerns/mentionable.rb', line 128 def matches_cross_reference_regex? reference_pattern = if !project || project.default_issues_tracker? ReferenceRegexes.default_pattern else ReferenceRegexes.external_pattern end self.class.mentionable_attrs.any? do |attr, _| __send__(attr) =~ reference_pattern # rubocop:disable GitlabSecurity/PublicSend end end |
#mentioned_users(current_user = nil) ⇒ Object
79 80 81 |
# File 'app/models/concerns/mentionable.rb', line 79 def mentioned_users(current_user = nil) all_references(current_user).users end |
#referenced_group_users(current_user = nil) ⇒ Object
106 107 108 |
# File 'app/models/concerns/mentionable.rb', line 106 def referenced_group_users(current_user = nil) User.joins(:group_members).where(members: { source_id: referenced_groups }).distinct end |
#referenced_groups(current_user = nil) ⇒ Object
95 96 97 98 99 100 101 102 103 104 |
# File 'app/models/concerns/mentionable.rb', line 95 def referenced_groups(current_user = nil) # TODO: IMPORTANT: Revisit before using it. # Check DB data for max mentioned groups per mentionable: # # select issue_id, count(mentions_count.men_gr_id) gr_count from # (select DISTINCT unnest(mentioned_groups_ids) as men_gr_id, issue_id # from issue_user_mentions group by issue_id, mentioned_groups_ids) as mentions_count # group by mentions_count.issue_id order by gr_count desc limit 10 Group.where(id: user_mentions.select("unnest(mentioned_groups_ids)")).public_or_visible_to_user(current_user) end |
#referenced_mentionables(current_user = self.author) ⇒ Object
Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
115 116 117 118 119 120 121 122 123 124 |
# File 'app/models/concerns/mentionable.rb', line 115 def referenced_mentionables(current_user = self.) return [] unless matches_cross_reference_regex? refs = all_references(current_user) # 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. extracted_mentionables(refs).reject { |ref| ref == local_reference } end |
#referenced_project_users(current_user = nil) ⇒ Object
91 92 93 |
# File 'app/models/concerns/mentionable.rb', line 91 def referenced_project_users(current_user = nil) User.joins(:project_members).where(members: { source_id: referenced_projects(current_user) }).distinct end |
#referenced_projects(current_user = nil) ⇒ Object
87 88 89 |
# File 'app/models/concerns/mentionable.rb', line 87 def referenced_projects(current_user = nil) Project.where(id: user_mentions.select("unnest(mentioned_projects_ids)")).public_or_visible_to_user(current_user) end |
#referenced_users ⇒ Object
83 84 85 |
# File 'app/models/concerns/mentionable.rb', line 83 def referenced_users User.where(id: user_mentions.select("unnest(mentioned_users_ids)")) end |
#user_mention_class ⇒ Object
164 165 166 |
# File 'app/models/concerns/mentionable.rb', line 164 def user_mention_class user_mention_association.klass end |
#user_mention_identifier ⇒ Object
Identifier for the user mention that is parsed from model description rather then its related notes. Models that have a description attribute like Issue, MergeRequest, Epic, Snippet may have such a user mention. Other mentionable models like DesignManagement::Design, will never have such record as those do not have a description attribute.
172 173 174 175 176 177 |
# File 'app/models/concerns/mentionable.rb', line 172 def user_mention_identifier { user_mention_association.foreign_key => id, note_id: nil } end |