Commit 925dc592 authored by Douwe Maan's avatar Douwe Maan

Cache rendered contents of issues, MRs and notes

parent 539de0dd
...@@ -46,7 +46,8 @@ module Issuable ...@@ -46,7 +46,8 @@ module Issuable
allow_nil: true, allow_nil: true,
prefix: true prefix: true
attr_mentionable :title, :description attr_mentionable :title
attr_mentionable :description, cache: true
participant :author, :assignee, :notes participant :author, :assignee, :notes
end end
......
...@@ -10,8 +10,9 @@ module Mentionable ...@@ -10,8 +10,9 @@ module Mentionable
module ClassMethods module ClassMethods
# Indicate which attributes of the Mentionable to search for GFM references. # Indicate which attributes of the Mentionable to search for GFM references.
def attr_mentionable(*attrs) def attr_mentionable(attr, options = {})
mentionable_attrs.concat(attrs.map(&:to_s)) attr = attr.to_s
mentionable_attrs << [attr, options]
end end
# Accessor for attributes marked mentionable. # Accessor for attributes marked mentionable.
...@@ -37,11 +38,6 @@ module Mentionable ...@@ -37,11 +38,6 @@ module Mentionable
"#{friendly_name} #{to_reference(from_project)}" "#{friendly_name} #{to_reference(from_project)}"
end end
# Construct a String that contains possible GFM references.
def mentionable_text
self.class.mentionable_attrs.map { |attr| send(attr) }.compact.join("\n\n")
end
# The GFM reference to this Mentionable, which shouldn't be included in its #references. # The GFM reference to this Mentionable, which shouldn't be included in its #references.
def local_reference def local_reference
self self
...@@ -54,20 +50,33 @@ module Mentionable ...@@ -54,20 +50,33 @@ module Mentionable
end end
def mentioned_users(current_user = nil, load_lazy_references: true) def mentioned_users(current_user = nil, load_lazy_references: true)
return [] if mentionable_text.blank? # TODO: Douwe: Will be simplified when the "Simplify ..." MR is merged.
ext = Gitlab::ReferenceExtractor.new(self.project, current_user, load_lazy_references: load_lazy_references) ext = Gitlab::ReferenceExtractor.new(self.project, current_user, load_lazy_references: load_lazy_references)
ext.analyze(mentionable_text) self.class.mentionable_attrs.each do |attr, options|
ext.users.uniq text = send(attr)
cache_key = [self, attr] if options[:cache]
ext.analyze(text, cache_key: cache_key, pipeline: options[:pipeline])
end
ext.users
end end
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference. # Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
def references(p = project, current_user = self.author, text = mentionable_text, load_lazy_references: true) def references(p = project, current_user = self.author, text = nil, load_lazy_references: true)
return [] if text.blank? return [] if text.blank?
ext = Gitlab::ReferenceExtractor.new(p, current_user, load_lazy_references: load_lazy_references) ext = Gitlab::ReferenceExtractor.new(p, current_user, load_lazy_references: load_lazy_references)
if text
ext.analyze(text) ext.analyze(text)
(ext.issues + ext.merge_requests + ext.commits).uniq - [local_reference] else
self.class.mentionable_attrs.each do |attr, options|
text = send(attr)
cache_key = [self, attr] if options[:cache]
ext.analyze(text, cache_key: cache_key)
end
end
(ext.issues + ext.merge_requests + ext.commits) - [local_reference]
end end
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+. # Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
...@@ -111,7 +120,7 @@ module Mentionable ...@@ -111,7 +120,7 @@ module Mentionable
def detect_mentionable_changes def detect_mentionable_changes
source = (changes.present? ? changes : previous_changes).dup source = (changes.present? ? changes : previous_changes).dup
mentionable = self.class.mentionable_attrs mentionable = self.class.mentionable_attrs.map { |attr, options| attr }
# Only include changed fields that are mentionable # Only include changed fields that are mentionable
source.select { |key, val| mentionable.include?(key) } source.select { |key, val| mentionable.include?(key) }
......
...@@ -28,7 +28,7 @@ class Note < ActiveRecord::Base ...@@ -28,7 +28,7 @@ class Note < ActiveRecord::Base
default_value_for :system, false default_value_for :system, false
attr_mentionable :note attr_mentionable :note, cache: true, pipeline: :note
participant :author participant :author
belongs_to :project belongs_to :project
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
.description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''} .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''}
.wiki .wiki
= preserve do = preserve do
= markdown(@issue.description) = markdown(@issue.description, cache_key: [@issue, "description"])
%textarea.hidden.js-task-list-field %textarea.hidden.js-task-list-field
= @issue.description = @issue.description
......
...@@ -7,6 +7,6 @@ ...@@ -7,6 +7,6 @@
.description{class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : ''} .description{class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : ''}
.wiki .wiki
= preserve do = preserve do
= markdown(@merge_request.description) = markdown(@merge_request.description, cache_key: [@merge_request, "description"])
%textarea.hidden.js-task-list-field %textarea.hidden.js-task-list-field
= @merge_request.description = @merge_request.description
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
.note-body{class: note_editable?(note) ? 'js-task-list-container' : ''} .note-body{class: note_editable?(note) ? 'js-task-list-container' : ''}
.note-text .note-text
= preserve do = preserve do
= markdown(note.note, {no_header_anchors: true}) = markdown(note.note, pipeline: :note, cache_key: [note, "note"])
- unless note.system? - unless note.system?
-# System notes can't be edited -# System notes can't be edited
= render 'projects/notes/edit_form', note: note = render 'projects/notes/edit_form', note: note
......
...@@ -20,6 +20,8 @@ module Gitlab ...@@ -20,6 +20,8 @@ module Gitlab
# #
# Returns an HTML-safe String # Returns an HTML-safe String
def self.render(text, context = {}) def self.render(text, context = {})
context[:pipeline] ||= :full
cache_key = context.delete(:cache_key) cache_key = context.delete(:cache_key)
cache_key = full_cache_key(cache_key, context[:pipeline]) cache_key = full_cache_key(cache_key, context[:pipeline])
...@@ -33,7 +35,7 @@ module Gitlab ...@@ -33,7 +35,7 @@ module Gitlab
end end
def self.render_result(text, context = {}) def self.render_result(text, context = {})
pipeline = context[:pipeline] || :full pipeline = context[:pipeline] ||= :full
html_pipeline = html_pipelines[pipeline] html_pipeline = html_pipelines[pipeline]
...@@ -129,6 +131,7 @@ module Gitlab ...@@ -129,6 +131,7 @@ module Gitlab
atom: :full, atom: :full,
email: :full, email: :full,
description: :full, description: :full,
note: :full,
single_line: :gfm, single_line: :gfm,
asciidoc: [ asciidoc: [
...@@ -170,6 +173,13 @@ module Gitlab ...@@ -170,6 +173,13 @@ module Gitlab
only_path: false only_path: false
} }
], ],
note: [
:full,
{
# TableOfContentsFilter
no_header_anchors: true
}
],
description: [ description: [
:full, :full,
{ {
......
...@@ -9,13 +9,12 @@ module Gitlab ...@@ -9,13 +9,12 @@ module Gitlab
@project = project @project = project
@current_user = current_user @current_user = current_user
@load_lazy_references = load_lazy_references @load_lazy_references = load_lazy_references
end
def analyze(text, cache_key: nil) @texts = []
references.clear end
@pipeline = Gitlab::Markdown.cached?(cache_key, pipeline: :full) ? :full : :plain_markdown def analyze(text, options = {})
@html = Gitlab::Markdown.render(text, project: project, cache_key: cache_key, pipeline: @pipeline) @texts << Gitlab::Markdown.render(text, options.merge(project: project))
end end
%i(user label issue merge_request snippet commit commit_range).each do |type| %i(user label issue merge_request snippet commit commit_range).each do |type|
...@@ -46,7 +45,7 @@ module Gitlab ...@@ -46,7 +45,7 @@ module Gitlab
filter = Gitlab::Markdown.const_get(klass) filter = Gitlab::Markdown.const_get(klass)
context = { context = {
pipeline: [:reference_extraction], pipeline: :reference_extraction,
project: project, project: project,
current_user: current_user, current_user: current_user,
...@@ -56,10 +55,11 @@ module Gitlab ...@@ -56,10 +55,11 @@ module Gitlab
reference_filter: filter reference_filter: filter
} }
context[:pipeline].unshift(filter) unless @pipeline == :full values = @texts.flat_map do |html|
text_context = context.dup
result = Gitlab::Markdown.render_result(@html, context) result = Gitlab::Markdown.render_result(html, text_context)
values = result[:references][filter_type].uniq result[:references][filter_type]
end.uniq
if @load_lazy_references if @load_lazy_references
values = Gitlab::Markdown::ReferenceFilter::LazyReference.load(values).uniq values = Gitlab::Markdown::ReferenceFilter::LazyReference.load(values).uniq
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment