Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
a9fb9fdc
Commit
a9fb9fdc
authored
Feb 03, 2022
by
Vitali Tatarintev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add a timeline event pipeline filter to TimelineEvent
Changelog: added EE: true
parent
0175304d
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
221 additions
and
4 deletions
+221
-4
ee/app/models/incident_management/timeline_event.rb
ee/app/models/incident_management/timeline_event.rb
+1
-2
ee/lib/banzai/filter/image_attachment_link_filter.rb
ee/lib/banzai/filter/image_attachment_link_filter.rb
+33
-0
ee/lib/banzai/pipeline/timeline_event_pipeline.rb
ee/lib/banzai/pipeline/timeline_event_pipeline.rb
+44
-0
ee/spec/lib/banzai/filter/image_attachment_link_filter_spec.rb
...ec/lib/banzai/filter/image_attachment_link_filter_spec.rb
+60
-0
ee/spec/lib/banzai/pipeline/timeline_event_pipeline_spec.rb
ee/spec/lib/banzai/pipeline/timeline_event_pipeline_spec.rb
+79
-0
ee/spec/models/incident_management/timeline_event_spec.rb
ee/spec/models/incident_management/timeline_event_spec.rb
+4
-2
No files found.
ee/app/models/incident_management/timeline_event.rb
View file @
a9fb9fdc
...
...
@@ -6,8 +6,7 @@ module IncidentManagement
self
.
table_name
=
'incident_management_timeline_events'
# TODO: Implement custom pipeline https://gitlab.com/gitlab-org/gitlab/-/issues/351214
cache_markdown_field
:note
,
pipeline: :note
,
issuable_reference_expansion_enabled:
true
cache_markdown_field
:note
,
pipeline: :timeline_event
,
issuable_reference_expansion_enabled:
true
belongs_to
:project
belongs_to
:author
,
class_name:
'User'
,
foreign_key: :author_id
...
...
ee/lib/banzai/filter/image_attachment_link_filter.rb
0 → 100644
View file @
a9fb9fdc
# frozen_string_literal: true
# Generated HTML is transformed back to GFM by app/assets/javascripts/behaviors/markdown/nodes/image.js
module
Banzai
module
Filter
# HTML filter that wraps links around inline images and replaces image with a link.
class
ImageAttachmentLinkFilter
<
HTML
::
Pipeline
::
Filter
# Find every image that isn't already wrapped in an `a` tag, create
# a new node (a link to the image source), copy the image alternative text as a child
# of the anchor, and then replace the img with the link-wrapped version.
def
call
doc
.
xpath
(
'descendant-or-self::img[not(ancestor::a)]'
).
each
do
|
img
|
link
=
doc
.
document
.
create_element
(
'a'
,
class:
'with-attachment-icon'
,
href:
img
[
'data-src'
]
||
img
[
'src'
],
target:
'_blank'
,
rel:
'noopener noreferrer'
)
# make sure the original non-proxied src carries over to the link
link
[
'data-canonical-src'
]
=
img
[
'data-canonical-src'
]
if
img
[
'data-canonical-src'
]
link
.
children
=
img
[
'alt'
]
||
img
[
'data-src'
]
||
img
[
'src'
]
img
.
replace
(
link
)
end
doc
end
end
end
end
ee/lib/banzai/pipeline/timeline_event_pipeline.rb
0 → 100644
View file @
a9fb9fdc
# frozen_string_literal: true
module
Banzai
module
Pipeline
class
TimelineEventPipeline
<
BasePipeline
ALLOWLIST
=
Banzai
::
Filter
::
SanitizationFilter
::
LIMITED
.
deep_dup
.
merge
(
elements:
%w(p b i strong em pre code a img)
)
def
self
.
filters
@filters
||=
FilterArray
[
Filter
::
MarkdownFilter
,
Filter
::
EmojiFilter
,
Filter
::
ExternalLinkFilter
,
Filter
::
ImageAttachmentLinkFilter
,
Filter
::
SanitizationFilter
,
*
reference_filters
]
end
def
self
.
reference_filters
[
Filter
::
References
::
UserReferenceFilter
,
Filter
::
References
::
IssueReferenceFilter
,
Filter
::
References
::
ExternalIssueReferenceFilter
,
Filter
::
References
::
MergeRequestReferenceFilter
,
Filter
::
References
::
SnippetReferenceFilter
,
Filter
::
References
::
CommitRangeReferenceFilter
,
Filter
::
References
::
CommitReferenceFilter
,
Filter
::
References
::
AlertReferenceFilter
,
Filter
::
References
::
FeatureFlagReferenceFilter
]
end
def
self
.
transform_context
(
context
)
Filter
::
AssetProxyFilter
.
transform_context
(
context
).
merge
(
only_path:
true
,
no_sourcepos:
true
,
allowlist:
ALLOWLIST
)
end
end
end
end
ee/spec/lib/banzai/filter/image_attachment_link_filter_spec.rb
0 → 100644
View file @
a9fb9fdc
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Banzai
::
Filter
::
ImageAttachmentLinkFilter
do
include
FilterSpecHelper
let
(
:path
)
{
'/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'
}
def
image
(
path
,
alt:
nil
)
alt_tag
=
alt
?
%Q{alt="
#{
alt
}
"}
:
""
%(<img src="#{path}" #{alt_tag} />)
end
it
'replaces the image with link to image src'
,
:aggregate_failures
do
doc
=
filter
(
image
(
path
))
expect
(
doc
.
to_html
).
to
match
(
%r{^<a[^>]*>
#{
path
}
</a>$}
)
expect
(
doc
.
at_css
(
'a'
)[
'href'
]).
to
eq
(
path
)
end
it
'uses image alt as a link text'
,
:aggregate_failures
do
doc
=
filter
(
image
(
path
,
alt:
'My image'
))
expect
(
doc
.
to_html
).
to
match
(
%r{^<a[^>]*>My image</a>$}
)
expect
(
doc
.
at_css
(
'a'
)[
'href'
]).
to
eq
(
path
)
end
it
'adds attachment icon class to the link'
do
doc
=
filter
(
image
(
path
))
expect
(
doc
.
at_css
(
'a'
)[
'class'
]).
to
match
(
%r{with-attachment-icon}
)
end
it
'does not wrap a duplicate link'
do
doc
=
filter
(
%Q(<a href="/whatever">
#{
image
(
path
)
}
</a>)
)
expect
(
doc
.
to_html
).
to
match
(
%r{^<a href="/whatever"><img[^>]*></a>$}
)
end
it
'works with external images'
do
external_path
=
'https://i.imgur.com/DfssX9C.jpg'
doc
=
filter
(
image
(
external_path
))
expect
(
doc
.
at_css
(
'a'
)[
'href'
]).
to
eq
(
external_path
)
end
it
'works with inline images'
do
doc
=
filter
(
%Q(<p>test
#{
image
(
path
)
}
inline</p>)
)
expect
(
doc
.
to_html
).
to
match
(
%r{^<p>test <a[^>]*>
#{
path
}
</a> inline</p>$}
)
end
it
'keep the data-canonical-src'
do
data_canonical_src
=
"http://example.com/test.png"
doc
=
filter
(
%Q(<img src="http://assets.example.com/6cd/4d7" data-canonical-src="
#{
data_canonical_src
}
" />)
)
expect
(
doc
.
at_css
(
'a'
)[
'data-canonical-src'
]).
to
eq
(
data_canonical_src
)
end
end
ee/spec/lib/banzai/pipeline/timeline_event_pipeline_spec.rb
0 → 100644
View file @
a9fb9fdc
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Banzai
::
Pipeline
::
TimelineEventPipeline
do
let_it_be
(
:project
)
{
create
(
:project
)
}
describe
'.reference_filters'
do
it
'contains required reference filters'
do
expect
(
described_class
.
reference_filters
).
to
contain_exactly
(
Banzai
::
Filter
::
References
::
UserReferenceFilter
,
Banzai
::
Filter
::
References
::
IssueReferenceFilter
,
Banzai
::
Filter
::
References
::
ExternalIssueReferenceFilter
,
Banzai
::
Filter
::
References
::
MergeRequestReferenceFilter
,
Banzai
::
Filter
::
References
::
SnippetReferenceFilter
,
Banzai
::
Filter
::
References
::
CommitRangeReferenceFilter
,
Banzai
::
Filter
::
References
::
CommitReferenceFilter
,
Banzai
::
Filter
::
References
::
AlertReferenceFilter
,
Banzai
::
Filter
::
References
::
FeatureFlagReferenceFilter
)
end
end
describe
'.to_html'
do
subject
(
:output
)
{
described_class
.
to_html
(
markdown
,
project:
project
)
}
context
'when markdown contains font style transformations'
do
let
(
:markdown
)
{
'**bold** _italic_ `code`'
}
it
{
is_expected
.
to
eq
(
'<p><strong>bold</strong> <em>italic</em> <code>code</code></p>'
)
}
end
context
'when markdown contains not allowed HTML tags'
do
let
(
:markdown
)
{
'<div>div</div><h1>h1</h1>'
}
it
'filters out not allowed tags'
do
is_expected
.
to
eq
(
' div h1 '
)
end
end
context
'when markdown contains links'
do
let
(
:markdown
)
{
'[GitLab](https://gitlab.com)'
}
it
{
is_expected
.
to
eq
(
%q(<p><a href="https://gitlab.com" target="_blank">GitLab</a></p>)
)
}
end
context
'when markdown contains images'
do
let
(
:markdown
)
{
'![Name](/path/to/image.png)'
}
it
'replaces image with a link to the image'
do
is_expected
.
to
eq
(
%q{<p><a class="with-attachment-icon" href="/path/to/image.png" target="_blank">Name</a></p>}
)
end
end
context
'when markdown contains emojis'
do
let
(
:markdown
)
{
':+1:👍'
}
it
{
is_expected
.
to
eq
(
'<p>👍👍</p>'
)
}
end
context
'when markdown contains a reference to an issue'
do
let!
(
:issue
)
{
create
(
:issue
,
project:
project
)
}
let
(
:markdown
)
{
"issue #
#{
issue
.
iid
}
"
}
it
'contains a link to the issue'
do
is_expected
.
to
match
(
%r(<p>issue <a
\s
href="[
\w\/
]+-
\/
issues
\/
#{
issue
.
iid
}
".*>#
#{
issue
.
iid
}
<
\/
a><
\/
p>)
)
end
end
context
'when markdown contains a reference to a merge request'
do
let!
(
:mr
)
{
create
(
:merge_request
,
source_project:
project
,
target_project:
project
)
}
let
(
:markdown
)
{
"MR !
#{
mr
.
iid
}
"
}
it
'contains a link to the merge request'
do
is_expected
.
to
match
(
%r(<p>MR <a
\s
href="[
\w\/
]+-
\/
merge_requests
\/
#{
mr
.
iid
}
".*>!
#{
mr
.
iid
}
<
\/
a><
\/
p>)
)
end
end
end
end
ee/spec/models/incident_management/timeline_event_spec.rb
View file @
a9fb9fdc
...
...
@@ -41,8 +41,10 @@ RSpec.describe IncidentManagement::TimelineEvent do
end
describe
'#cache_markdown_field'
do
let
(
:note
)
{
'<p>some html</p>'
}
let
(
:expected_note_html
)
{
'<p dir="auto">some html</p>'
}
let
(
:note
)
{
'note **bold** _italic_ `code` ![image](/path/img.png) :+1:👍'
}
let
(
:expected_note_html
)
do
'<p>note <strong>bold</strong> <em>italic</em> <code>code</code> <a class="with-attachment-icon" href="/path/img.png" target="_blank">image</a> 👍👍</p>'
end
before
do
allow
(
Banzai
::
Renderer
).
to
receive
(
:cacheless_render_field
).
and_call_original
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment