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
f9475e29
Commit
f9475e29
authored
Sep 04, 2018
by
Francisco Javier López
Committed by
Douwe Maan
Sep 04, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Uploads to wiki stored inside the wiki git repository
parent
0689900c
Changes
24
Show whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
906 additions
and
85 deletions
+906
-85
app/helpers/wiki_helper.rb
app/helpers/wiki_helper.rb
+6
-0
app/services/files/base_service.rb
app/services/files/base_service.rb
+2
-2
app/services/wikis/create_attachment_service.rb
app/services/wikis/create_attachment_service.rb
+71
-0
app/uploaders/file_uploader.rb
app/uploaders/file_uploader.rb
+0
-10
app/uploaders/uploader_helper.rb
app/uploaders/uploader_helper.rb
+1
-26
app/views/projects/wikis/edit.html.haml
app/views/projects/wikis/edit.html.haml
+5
-0
changelogs/unreleased/fj-33475-files-inside-wiki-repo.yml
changelogs/unreleased/fj-33475-files-inside-wiki-repo.yml
+5
-0
doc/api/wikis.md
doc/api/wikis.md
+41
-3
lib/api/entities.rb
lib/api/entities.rb
+22
-0
lib/api/wikis.rb
lib/api/wikis.rb
+31
-0
lib/banzai/filter/wiki_link_filter.rb
lib/banzai/filter/wiki_link_filter.rb
+6
-4
lib/banzai/filter/wiki_link_filter/rewriter.rb
lib/banzai/filter/wiki_link_filter/rewriter.rb
+17
-4
lib/gitlab/file_markdown_link_builder.rb
lib/gitlab/file_markdown_link_builder.rb
+21
-0
lib/gitlab/file_type_detection.rb
lib/gitlab/file_type_detection.rb
+43
-0
spec/features/projects/wiki/user_creates_wiki_page_spec.rb
spec/features/projects/wiki/user_creates_wiki_page_spec.rb
+2
-0
spec/features/projects/wiki/user_updates_wiki_page_spec.rb
spec/features/projects/wiki/user_updates_wiki_page_spec.rb
+12
-14
spec/features/projects/wiki/user_views_wiki_page_spec.rb
spec/features/projects/wiki/user_views_wiki_page_spec.rb
+1
-1
spec/lib/banzai/filter/wiki_link_filter_spec.rb
spec/lib/banzai/filter/wiki_link_filter_spec.rb
+40
-0
spec/lib/gitlab/file_markdown_link_builder_spec.rb
spec/lib/gitlab/file_markdown_link_builder_spec.rb
+80
-0
spec/lib/gitlab/file_type_detection_spec.rb
spec/lib/gitlab/file_type_detection_spec.rb
+82
-0
spec/requests/api/wikis_spec.rb
spec/requests/api/wikis_spec.rb
+124
-0
spec/services/wikis/create_attachment_service_spec.rb
spec/services/wikis/create_attachment_service_spec.rb
+202
-0
spec/support/shared_examples/wiki_file_attachments_examples.rb
...support/shared_examples/wiki_file_attachments_examples.rb
+88
-0
spec/uploaders/uploader_helper_spec.rb
spec/uploaders/uploader_helper_spec.rb
+4
-21
No files found.
app/helpers/wiki_helper.rb
View file @
f9475e29
module
WikiHelper
include
API
::
Helpers
::
RelatedResourcesHelpers
# Produces a pure text breadcrumb for a given page.
#
# page_slug - The slug of a WikiPage object.
...
...
@@ -39,4 +41,8 @@ module WikiHelper
end
end
end
def
wiki_attachment_upload_url
expose_url
(
api_v4_projects_wikis_attachments_path
(
id:
@project
.
id
))
end
end
app/services/files/base_service.rb
View file @
f9475e29
...
...
@@ -7,8 +7,8 @@ module Files
def
initialize
(
*
args
)
super
@author_email
=
params
[
:author_email
]
@author_name
=
params
[
:author_name
]
@author_email
=
params
[
:author_email
]
||
current_user
&
.
email
@author_name
=
params
[
:author_name
]
||
current_user
&
.
name
@commit_message
=
params
[
:commit_message
]
@last_commit_sha
=
params
[
:last_commit_sha
]
...
...
app/services/wikis/create_attachment_service.rb
0 → 100644
View file @
f9475e29
# frozen_string_literal: true
module
Wikis
class
CreateAttachmentService
<
Files
::
CreateService
ATTACHMENT_PATH
=
'uploads'
.
freeze
MAX_FILENAME_LENGTH
=
255
delegate
:wiki
,
to: :project
delegate
:repository
,
to: :wiki
def
initialize
(
*
args
)
super
@file_name
=
truncate_file_name
(
params
[
:file_name
])
@file_path
=
File
.
join
(
ATTACHMENT_PATH
,
SecureRandom
.
hex
,
@file_name
)
if
@file_name
@commit_message
||=
"Upload attachment
#{
@file_name
}
"
@branch_name
||=
wiki
.
default_branch
end
def
create_commit!
commit_result
(
create_transformed_commit
(
@file_content
))
end
private
def
truncate_file_name
(
file_name
)
return
unless
file_name
.
present?
return
file_name
if
file_name
.
length
<=
MAX_FILENAME_LENGTH
extension
=
File
.
extname
(
file_name
)
truncate_at
=
MAX_FILENAME_LENGTH
-
extension
.
length
-
1
base_name
=
File
.
basename
(
file_name
,
extension
)[
0
..
truncate_at
]
base_name
+
extension
end
def
validate!
validate_file_name!
validate_permissions!
end
def
validate_file_name!
raise_error
(
'The file name cannot be empty'
)
unless
@file_name
end
def
validate_permissions!
unless
can?
(
current_user
,
:create_wiki
,
project
)
raise_error
(
'You are not allowed to push to the wiki'
)
end
end
def
create_transformed_commit
(
content
)
repository
.
create_file
(
current_user
,
@file_path
,
content
,
message:
@commit_message
,
branch_name:
@branch_name
,
author_email:
@author_email
,
author_name:
@author_name
)
end
def
commit_result
(
commit_id
)
{
file_name:
@file_name
,
file_path:
@file_path
,
branch:
@branch_name
,
commit:
commit_id
}
end
end
end
app/uploaders/file_uploader.rb
View file @
f9475e29
...
...
@@ -122,12 +122,6 @@ class FileUploader < GitlabUploader
}
end
def
markdown_link
markdown
=
+
"[
#{
markdown_name
}
](
#{
secure_url
}
)"
markdown
.
prepend
(
"!"
)
if
image_or_video?
||
dangerous?
markdown
end
def
to_h
{
alt:
markdown_name
,
...
...
@@ -192,10 +186,6 @@ class FileUploader < GitlabUploader
storage
.
delete_dir!
(
store_dir
)
# only remove when empty
end
def
markdown_name
(
image_or_video?
?
File
.
basename
(
filename
,
File
.
extname
(
filename
))
:
filename
).
gsub
(
"]"
,
"
\\
]"
)
end
def
identifier
@identifier
||=
filename
end
...
...
app/uploaders/uploader_helper.rb
View file @
f9475e29
...
...
@@ -2,32 +2,7 @@
# Extra methods for uploader
module
UploaderHelper
IMAGE_EXT
=
%w[png jpg jpeg gif bmp tiff ico]
.
freeze
# We recommend using the .mp4 format over .mov. Videos in .mov format can
# still be used but you really need to make sure they are served with the
# proper MIME type video/mp4 and not video/quicktime or your videos won't play
# on IE >= 9.
# http://archive.sublimevideo.info/20150912/docs.sublimevideo.net/troubleshooting.html
VIDEO_EXT
=
%w[mp4 m4v mov webm ogv]
.
freeze
# These extension types can contain dangerous code and should only be embedded inline with
# proper filtering. They should always be tagged as "Content-Disposition: attachment", not "inline".
DANGEROUS_EXT
=
%w[svg]
.
freeze
def
image?
extension_match?
(
IMAGE_EXT
)
end
def
video?
extension_match?
(
VIDEO_EXT
)
end
def
image_or_video?
image?
||
video?
end
def
dangerous?
extension_match?
(
DANGEROUS_EXT
)
end
include
Gitlab
::
FileMarkdownLinkBuilder
private
...
...
app/views/projects/wikis/edit.html.haml
View file @
f9475e29
...
...
@@ -41,3 +41,8 @@
=
render
'sidebar'
#delete-wiki-modal
.modal.fade
-
content_for
:scripts_body
do
-# haml-lint:disable InlineJavaScript
:javascript
window
.
uploads_path
=
"
#{
wiki_attachment_upload_url
}
"
;
changelogs/unreleased/fj-33475-files-inside-wiki-repo.yml
0 → 100644
View file @
f9475e29
---
title
:
Store wiki uploads inside git repository
merge_request
:
21362
author
:
type
:
added
doc/api/wikis.md
View file @
f9475e29
...
...
@@ -157,3 +157,41 @@ curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gi
On success the HTTP status code is
`204`
and no JSON response is expected.
[
ce-13372
]:
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13372
## Upload an attachment to the wiki repository
Uploads a file to the attachment folder inside the wiki's repository. The
attachment folder is the
`uploads`
folder.
```
POST /projects/:id/wikis/attachments
```
| Attribute | Type | Required | Description |
| ------------- | ------- | -------- | ---------------------------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
|
|
`file`
| string | yes | The attachment to be uploaded |
|
`branch`
| string | no | The name of the branch. Defaults to the wiki repository default branch |
To upload a file from your filesystem, use the
`--form`
argument. This causes
cURL to post data using the header
`Content-Type: multipart/form-data`
.
The
`file=`
parameter must point to a file on your filesystem and be preceded
by
`@`
. For example:
```
bash
curl
--request
POST
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
--form
"file=@dk.png"
https://gitlab.example.com/api/v4/projects/1/wikis/attachments
```
Example response:
```
json
{
"file_name"
:
"dk.png"
,
"file_path"
:
"uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png"
,
"branch"
:
"master"
,
"link"
:
{
"url"
:
"uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png"
,
"markdown"
:
"![dk](uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png)"
}
}
```
lib/api/entities.rb
View file @
f9475e29
...
...
@@ -10,6 +10,28 @@ module API
expose
:content
end
class
WikiAttachment
<
Grape
::
Entity
include
Gitlab
::
FileMarkdownLinkBuilder
expose
:file_name
expose
:file_path
expose
:branch
expose
:link
do
expose
:file_path
,
as: :url
expose
:markdown
do
|
_entity
|
self
.
markdown_link
end
end
def
filename
object
.
file_name
end
def
secure_url
object
.
file_path
end
end
class
UserSafe
<
Grape
::
Entity
expose
:id
,
:name
,
:username
end
...
...
lib/api/wikis.rb
View file @
f9475e29
module
API
class
Wikis
<
Grape
::
API
helpers
do
def
commit_params
(
attrs
)
{
file_name:
attrs
[
:file
][
:filename
],
file_content:
File
.
read
(
attrs
[
:file
][
:tempfile
]),
branch_name:
attrs
[
:branch
]
}
end
params
:wiki_page_params
do
requires
:content
,
type:
String
,
desc:
'Content of a wiki page'
requires
:title
,
type:
String
,
desc:
'Title of a wiki page'
...
...
@@ -84,6 +92,29 @@ module API
status
204
WikiPages
::
DestroyService
.
new
(
user_project
,
current_user
).
execute
(
wiki_page
)
end
desc
'Upload an attachment to the wiki repository'
do
detail
'This feature was introduced in GitLab 11.3.'
success
Entities
::
WikiAttachment
end
params
do
requires
:file
,
type:
File
,
desc:
'The attachment file to be uploaded'
optional
:branch
,
type:
String
,
desc:
'The name of the branch'
end
post
":id/wikis/attachments"
,
requirements:
API
::
PROJECT_ENDPOINT_REQUIREMENTS
do
authorize!
:create_wiki
,
user_project
result
=
::
Wikis
::
CreateAttachmentService
.
new
(
user_project
,
current_user
,
commit_params
(
declared_params
(
include_missing:
false
))).
execute
if
result
[
:status
]
==
:success
status
(
201
)
present
OpenStruct
.
new
(
result
[
:result
]),
with:
Entities
::
WikiAttachment
else
render_api_error!
(
result
[
:message
],
400
)
end
end
end
end
end
lib/banzai/filter/wiki_link_filter.rb
View file @
f9475e29
# frozen_string_literal: true
require
'uri'
module
Banzai
module
Filter
# HTML filter that "fixes" links to pages/files in a wiki.
...
...
@@ -13,8 +11,12 @@ module Banzai
def
call
return
doc
unless
project_wiki?
doc
.
search
(
'a:not(.gfm)'
).
each
do
|
el
|
process_link_attr
el
.
attribute
(
'href'
)
doc
.
search
(
'a:not(.gfm)'
).
each
{
|
el
|
process_link_attr
(
el
.
attribute
(
'href'
))
}
doc
.
search
(
'video'
).
each
{
|
el
|
process_link_attr
(
el
.
attribute
(
'src'
))
}
doc
.
search
(
'img'
).
each
do
|
el
|
attr
=
el
.
attribute
(
'data-src'
)
||
el
.
attribute
(
'src'
)
process_link_attr
(
attr
)
end
doc
...
...
lib/banzai/filter/wiki_link_filter/rewriter.rb
View file @
f9475e29
...
...
@@ -10,11 +10,16 @@ module Banzai
def
apply_rules
# Special case: relative URLs beginning with `/uploads/` refer to
# user-uploaded files
and
will be handled elsewhere.
return
@uri
.
to_s
if
@uri
.
relative?
&&
@uri
.
path
.
starts_with?
(
'/uploads/'
)
# user-uploaded files will be handled elsewhere.
return
@uri
.
to_s
if
public_upload?
# Special case: relative URLs beginning with Wikis::CreateAttachmentService::ATTACHMENT_PATH
# refer to user-uploaded files to the wiki repository.
unless
repository_upload?
apply_file_link_rules!
apply_hierarchical_link_rules!
end
apply_relative_link_rules!
@uri
.
to_s
end
...
...
@@ -39,6 +44,14 @@ module Banzai
@uri
=
Addressable
::
URI
.
parse
(
link
)
end
end
def
public_upload?
@uri
.
relative?
&&
@uri
.
path
.
starts_with?
(
'/uploads/'
)
end
def
repository_upload?
@uri
.
relative?
&&
@uri
.
path
.
starts_with?
(
Wikis
::
CreateAttachmentService
::
ATTACHMENT_PATH
)
end
end
end
end
...
...
lib/gitlab/file_markdown_link_builder.rb
0 → 100644
View file @
f9475e29
# Builds the markdown link of a file
# It needs the methods filename and secure_url (final destination url) to be defined.
module
Gitlab
module
FileMarkdownLinkBuilder
include
FileTypeDetection
def
markdown_link
return
unless
name
=
markdown_name
markdown
=
"[
#{
name
.
gsub
(
']'
,
'\\]'
)
}
](
#{
secure_url
}
)"
markdown
.
prepend
(
"!"
)
if
image_or_video?
||
dangerous?
markdown
end
def
markdown_name
return
unless
filename
.
present?
image_or_video?
?
File
.
basename
(
filename
,
File
.
extname
(
filename
))
:
filename
end
end
end
lib/gitlab/file_type_detection.rb
0 → 100644
View file @
f9475e29
# frozen_string_literal: true
# File helpers methods.
# It needs the method filename to be defined.
module
Gitlab
module
FileTypeDetection
IMAGE_EXT
=
%w[png jpg jpeg gif bmp tiff ico]
.
freeze
# We recommend using the .mp4 format over .mov. Videos in .mov format can
# still be used but you really need to make sure they are served with the
# proper MIME type video/mp4 and not video/quicktime or your videos won't play
# on IE >= 9.
# http://archive.sublimevideo.info/20150912/docs.sublimevideo.net/troubleshooting.html
VIDEO_EXT
=
%w[mp4 m4v mov webm ogv]
.
freeze
# These extension types can contain dangerous code and should only be embedded inline with
# proper filtering. They should always be tagged as "Content-Disposition: attachment", not "inline".
DANGEROUS_EXT
=
%w[svg]
.
freeze
def
image?
extension_match?
(
IMAGE_EXT
)
end
def
video?
extension_match?
(
VIDEO_EXT
)
end
def
image_or_video?
image?
||
video?
end
def
dangerous?
extension_match?
(
DANGEROUS_EXT
)
end
private
def
extension_match?
(
extensions
)
return
false
unless
filename
extension
=
File
.
extname
(
filename
).
delete
(
'.'
)
extensions
.
include?
(
extension
.
downcase
)
end
end
end
spec/features/projects/wiki/user_creates_wiki_page_spec.rb
View file @
f9475e29
...
...
@@ -146,6 +146,8 @@ describe "User creates wiki page" do
expect
(
page
).
to
have_selector
(
".katex"
,
count:
3
).
and
have_content
(
"2+2 is 4"
)
end
end
it_behaves_like
'wiki file attachments'
end
context
"in a group namespace"
,
:js
do
...
...
spec/features/projects/wiki/user_updates_wiki_page_spec.rb
View file @
f9475e29
...
...
@@ -3,6 +3,7 @@ require 'spec_helper'
describe
'User updates wiki page'
do
shared_examples
'wiki page user update'
do
let
(
:user
)
{
create
(
:user
)
}
before
do
project
.
add_maintainer
(
user
)
sign_in
(
user
)
...
...
@@ -55,6 +56,8 @@ describe 'User updates wiki page' do
expect
(
page
).
to
have_content
(
'Updated Wiki Content'
)
end
it_behaves_like
'wiki file attachments'
end
end
...
...
@@ -64,14 +67,14 @@ describe 'User updates wiki page' do
before
do
visit
(
project_wikis_path
(
project
))
click_link
(
'Edit'
)
end
context
'in a user namespace'
do
let
(
:project
)
{
create
(
:project
,
:wiki_repo
,
namespace:
user
.
namespace
)
}
it
'updates a page'
do
click_link
(
'Edit'
)
# Commit message field should have correct value.
expect
(
page
).
to
have_field
(
'wiki[message]'
,
with:
'Update home'
)
...
...
@@ -84,8 +87,6 @@ describe 'User updates wiki page' do
end
it
'shows a validation error message'
do
click_link
(
'Edit'
)
fill_in
(
:wiki_content
,
with:
''
)
click_button
(
'Save changes'
)
...
...
@@ -97,8 +98,6 @@ describe 'User updates wiki page' do
end
it
'shows the emoji autocompletion dropdown'
,
:js
do
click_link
(
'Edit'
)
find
(
'#wiki_content'
).
native
.
send_keys
(
''
)
fill_in
(
:wiki_content
,
with:
':'
)
...
...
@@ -106,8 +105,6 @@ describe 'User updates wiki page' do
end
it
'shows the error message'
do
click_link
(
'Edit'
)
wiki_page
.
update
(
content:
'Update'
)
click_button
(
'Save changes'
)
...
...
@@ -116,30 +113,27 @@ describe 'User updates wiki page' do
end
it
'updates a page'
do
click_on
(
'Edit'
)
fill_in
(
'Content'
,
with:
'Updated Wiki Content'
)
click_on
(
'Save changes'
)
expect
(
page
).
to
have_content
(
'Updated Wiki Content'
)
end
it
'cancels edititng of a page'
do
click_on
(
'Edit'
)
it
'cancels editing of a page'
do
page
.
within
(
:css
,
'.wiki-form .form-actions'
)
do
click_on
(
'Cancel'
)
end
expect
(
current_path
).
to
eq
(
project_wiki_path
(
project
,
wiki_page
))
end
it_behaves_like
'wiki file attachments'
end
context
'in a group namespace'
do
let
(
:project
)
{
create
(
:project
,
:wiki_repo
,
namespace:
create
(
:group
,
:public
))
}
it
'updates a page'
do
click_link
(
'Edit'
)
# Commit message field should have correct value.
expect
(
page
).
to
have_field
(
'wiki[message]'
,
with:
'Update home'
)
...
...
@@ -151,6 +145,8 @@ describe 'User updates wiki page' do
expect
(
page
).
to
have_content
(
"Last edited by
#{
user
.
name
}
"
)
expect
(
page
).
to
have_content
(
'My awesome wiki!'
)
end
it_behaves_like
'wiki file attachments'
end
end
...
...
@@ -222,6 +218,8 @@ describe 'User updates wiki page' do
expect
(
current_path
).
to
eq
(
project_wiki_path
(
project
,
"foo1/bar1/
#{
page_name
}
"
))
end
it_behaves_like
'wiki file attachments'
end
end
...
...
spec/features/projects/wiki/user_views_wiki_page_spec.rb
View file @
f9475e29
...
...
@@ -93,7 +93,7 @@ describe 'User views a wiki page' do
allow
(
wiki_file
).
to
receive
(
:mime_type
).
and_return
(
'image/jpeg'
)
allow_any_instance_of
(
ProjectWiki
).
to
receive
(
:find_file
).
with
(
'image.jpg'
,
nil
).
and_return
(
wiki_file
)
expect
(
page
).
to
have_xpath
(
'//img[@data-src="image.jpg"]'
)
expect
(
page
).
to
have_xpath
(
"//img[@data-src='
#{
project
.
wiki
.
wiki_base_path
}
/image.jpg']"
)
expect
(
page
).
to
have_link
(
'image'
,
href:
"
#{
project
.
wiki
.
wiki_base_path
}
/image.jpg"
)
click_on
(
'image'
)
...
...
spec/lib/banzai/filter/wiki_link_filter_spec.rb
View file @
f9475e29
...
...
@@ -7,6 +7,7 @@ describe Banzai::Filter::WikiLinkFilter do
let
(
:project
)
{
build_stubbed
(
:project
,
:public
,
name:
"wiki_link_project"
,
namespace:
namespace
)
}
let
(
:user
)
{
double
}
let
(
:wiki
)
{
ProjectWiki
.
new
(
project
,
user
)
}
let
(
:repository_upload_folder
)
{
Wikis
::
CreateAttachmentService
::
ATTACHMENT_PATH
}
it
"doesn't rewrite absolute links"
do
filtered_link
=
filter
(
"<a href='http://example.com:8000/'>Link</a>"
,
project_wiki:
wiki
).
children
[
0
]
...
...
@@ -20,6 +21,45 @@ describe Banzai::Filter::WikiLinkFilter do
expect
(
filtered_link
.
attribute
(
'href'
).
value
).
to
eq
(
'/uploads/a.test'
)
end
describe
"when links point to the
#{
Wikis
::
CreateAttachmentService
::
ATTACHMENT_PATH
}
folder"
do
context
'with an "a" html tag'
do
it
'rewrites links'
do
filtered_link
=
filter
(
"<a href='
#{
repository_upload_folder
}
/a.test'>Link</a>"
,
project_wiki:
wiki
).
children
[
0
]
expect
(
filtered_link
.
attribute
(
'href'
).
value
).
to
eq
(
"
#{
wiki
.
wiki_base_path
}
/
#{
repository_upload_folder
}
/a.test"
)
end
end
context
'with "img" html tag'
do
let
(
:path
)
{
"
#{
wiki
.
wiki_base_path
}
/
#{
repository_upload_folder
}
/a.jpg"
}
context
'inside an "a" html tag'
do
it
'rewrites links'
do
filtered_elements
=
filter
(
"<a href='
#{
repository_upload_folder
}
/a.jpg'><img src='
#{
repository_upload_folder
}
/a.jpg'>example</img></a>"
,
project_wiki:
wiki
)
expect
(
filtered_elements
.
search
(
'img'
).
first
.
attribute
(
'src'
).
value
).
to
eq
(
path
)
expect
(
filtered_elements
.
search
(
'a'
).
first
.
attribute
(
'href'
).
value
).
to
eq
(
path
)
end
end
context
'outside an "a" html tag'
do
it
'rewrites links'
do
filtered_link
=
filter
(
"<img src='
#{
repository_upload_folder
}
/a.jpg'>example</img>"
,
project_wiki:
wiki
).
children
[
0
]
expect
(
filtered_link
.
attribute
(
'src'
).
value
).
to
eq
(
path
)
end
end
end
context
'with "video" html tag'
do
it
'rewrites links'
do
filtered_link
=
filter
(
"<video src='
#{
repository_upload_folder
}
/a.mp4'></video>"
,
project_wiki:
wiki
).
children
[
0
]
expect
(
filtered_link
.
attribute
(
'src'
).
value
).
to
eq
(
"
#{
wiki
.
wiki_base_path
}
/
#{
repository_upload_folder
}
/a.mp4"
)
end
end
end
describe
"invalid links"
do
invalid_links
=
[
"http://:8080"
,
"http://"
,
"http://:8080/path"
]
...
...
spec/lib/gitlab/file_markdown_link_builder_spec.rb
0 → 100644
View file @
f9475e29
# frozen_string_literal: true
require
'rails_helper'
describe
Gitlab
::
FileMarkdownLinkBuilder
do
let
(
:custom_class
)
do
Class
.
new
do
include
Gitlab
::
FileMarkdownLinkBuilder
end
.
new
end
before
do
allow
(
custom_class
).
to
receive
(
:filename
).
and_return
(
filename
)
end
describe
'markdown_link'
do
let
(
:url
)
{
"/uploads/
#{
filename
}
"
}
before
do
allow
(
custom_class
).
to
receive
(
:secure_url
).
and_return
(
url
)
end
context
'when file name has the character ]'
do
let
(
:filename
)
{
'd]k.png'
}
it
'escapes the character'
do
expect
(
custom_class
.
markdown_link
).
to
eq
'![d\\]k](/uploads/d]k.png)'
end
end
context
'when file is an image or video'
do
let
(
:filename
)
{
'dk.png'
}
it
'returns preview markdown link'
do
expect
(
custom_class
.
markdown_link
).
to
eq
'![dk](/uploads/dk.png)'
end
end
context
'when file is not an image or video'
do
let
(
:filename
)
{
'dk.zip'
}
it
'returns markdown link'
do
expect
(
custom_class
.
markdown_link
).
to
eq
'[dk.zip](/uploads/dk.zip)'
end
end
context
'when file name is blank'
do
let
(
:filename
)
{
nil
}
it
'returns nil'
do
expect
(
custom_class
.
markdown_link
).
to
eq
nil
end
end
end
describe
'mardown_name'
do
context
'when file is an image or video'
do
let
(
:filename
)
{
'dk.png'
}
it
'retrieves the name without the extension'
do
expect
(
custom_class
.
markdown_name
).
to
eq
'dk'
end
end
context
'when file is not an image or video'
do
let
(
:filename
)
{
'dk.zip'
}
it
'retrieves the name with the extesion'
do
expect
(
custom_class
.
markdown_name
).
to
eq
'dk.zip'
end
end
context
'when file name is blank'
do
let
(
:filename
)
{
nil
}
it
'returns nil'
do
expect
(
custom_class
.
markdown_name
).
to
eq
nil
end
end
end
end
spec/lib/gitlab/file_type_detection_spec.rb
0 → 100644
View file @
f9475e29
# frozen_string_literal: true
require
'rails_helper'
describe
Gitlab
::
FileTypeDetection
do
def
upload_fixture
(
filename
)
fixture_file_upload
(
File
.
join
(
'spec'
,
'fixtures'
,
filename
))
end
describe
'#image_or_video?'
do
context
'when class is an uploader'
do
let
(
:uploader
)
do
example_uploader
=
Class
.
new
(
CarrierWave
::
Uploader
::
Base
)
do
include
Gitlab
::
FileTypeDetection
storage
:file
end
example_uploader
.
new
end
it
'returns true for an image file'
do
uploader
.
store!
(
upload_fixture
(
'dk.png'
))
expect
(
uploader
).
to
be_image_or_video
end
it
'returns true for a video file'
do
uploader
.
store!
(
upload_fixture
(
'video_sample.mp4'
))
expect
(
uploader
).
to
be_image_or_video
end
it
'returns false for other extensions'
do
uploader
.
store!
(
upload_fixture
(
'doc_sample.txt'
))
expect
(
uploader
).
not_to
be_image_or_video
end
it
'returns false if filename is blank'
do
uploader
.
store!
(
upload_fixture
(
'dk.png'
))
allow
(
uploader
).
to
receive
(
:filename
).
and_return
(
nil
)
expect
(
uploader
).
not_to
be_image_or_video
end
end
context
'when class is a regular class'
do
let
(
:custom_class
)
do
custom_class
=
Class
.
new
do
include
Gitlab
::
FileTypeDetection
end
custom_class
.
new
end
it
'returns true for an image file'
do
allow
(
custom_class
).
to
receive
(
:filename
).
and_return
(
'dk.png'
)
expect
(
custom_class
).
to
be_image_or_video
end
it
'returns true for a video file'
do
allow
(
custom_class
).
to
receive
(
:filename
).
and_return
(
'video_sample.mp4'
)
expect
(
custom_class
).
to
be_image_or_video
end
it
'returns false for other extensions'
do
allow
(
custom_class
).
to
receive
(
:filename
).
and_return
(
'doc_sample.txt'
)
expect
(
custom_class
).
not_to
be_image_or_video
end
it
'returns false if filename is blank'
do
allow
(
custom_class
).
to
receive
(
:filename
).
and_return
(
nil
)
expect
(
custom_class
).
not_to
be_image_or_video
end
end
end
end
spec/requests/api/wikis_spec.rb
View file @
f9475e29
...
...
@@ -139,6 +139,27 @@ describe API::Wikis do
end
end
shared_examples_for
'uploads wiki attachment'
do
it
'pushes attachment to the wiki repository'
do
allow
(
SecureRandom
).
to
receive
(
:hex
).
and_return
(
'fixed_hex'
)
post
(
api
(
url
,
user
),
payload
)
expect
(
response
).
to
have_gitlab_http_status
(
201
)
expect
(
json_response
).
to
eq
result_hash
.
deep_stringify_keys
end
it
'responds with validation error on empty file'
do
payload
.
delete
(
:file
)
post
(
api
(
url
,
user
),
payload
)
expect
(
response
).
to
have_gitlab_http_status
(
400
)
expect
(
json_response
.
size
).
to
eq
(
1
)
expect
(
json_response
[
'error'
]).
to
eq
(
'file is missing'
)
end
end
describe
'GET /projects/:id/wikis'
do
let
(
:url
)
{
"/projects/
#{
project
.
id
}
/wikis"
}
...
...
@@ -698,4 +719,107 @@ describe API::Wikis do
include_examples
'204 No Content'
end
end
describe
'POST /projects/:id/wikis/attachments'
do
let
(
:payload
)
{
{
file:
fixture_file_upload
(
'spec/fixtures/dk.png'
)
}
}
let
(
:url
)
{
"/projects/
#{
project
.
id
}
/wikis/attachments"
}
let
(
:file_path
)
{
"
#{
Wikis
::
CreateAttachmentService
::
ATTACHMENT_PATH
}
/fixed_hex/dk.png"
}
let
(
:result_hash
)
do
{
file_name:
'dk.png'
,
file_path:
file_path
,
branch:
'master'
,
link:
{
url:
file_path
,
markdown:
"![dk](
#{
file_path
}
)"
}
}
end
context
'when wiki is disabled'
do
let
(
:project
)
{
create
(
:project
,
:wiki_disabled
,
:wiki_repo
)
}
context
'when user is guest'
do
before
do
post
(
api
(
url
),
payload
)
end
include_examples
'404 Project Not Found'
end
context
'when user is developer'
do
before
do
project
.
add_developer
(
user
)
post
(
api
(
url
,
user
),
payload
)
end
include_examples
'403 Forbidden'
end
context
'when user is maintainer'
do
before
do
project
.
add_maintainer
(
user
)
post
(
api
(
url
,
user
),
payload
)
end
include_examples
'403 Forbidden'
end
end
context
'when wiki is available only for team members'
do
let
(
:project
)
{
create
(
:project
,
:wiki_private
,
:wiki_repo
)
}
context
'when user is guest'
do
before
do
post
(
api
(
url
),
payload
)
end
include_examples
'404 Project Not Found'
end
context
'when user is developer'
do
before
do
project
.
add_developer
(
user
)
end
include_examples
'uploads wiki attachment'
end
context
'when user is maintainer'
do
before
do
project
.
add_maintainer
(
user
)
end
include_examples
'uploads wiki attachment'
end
end
context
'when wiki is available for everyone with access'
do
let
(
:project
)
{
create
(
:project
,
:wiki_repo
)
}
context
'when user is guest'
do
before
do
post
(
api
(
url
),
payload
)
end
include_examples
'404 Project Not Found'
end
context
'when user is developer'
do
before
do
project
.
add_developer
(
user
)
end
include_examples
'uploads wiki attachment'
end
context
'when user is maintainer'
do
before
do
project
.
add_maintainer
(
user
)
end
include_examples
'uploads wiki attachment'
end
end
end
end
spec/services/wikis/create_attachment_service_spec.rb
0 → 100644
View file @
f9475e29
# frozen_string_literal: true
require
'spec_helper'
describe
Wikis
::
CreateAttachmentService
do
let
(
:project
)
{
create
(
:project
,
:wiki_repo
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:file_name
)
{
'filename.txt'
}
let
(
:file_path_regex
)
{
%r{
#{
described_class
::
ATTACHMENT_PATH
}
/
\h
{32}/
#{
file_name
}
}
}
let
(
:file_opts
)
do
{
file_name:
file_name
,
file_content:
'Content of attachment'
}
end
let
(
:opts
)
{
file_opts
}
subject
(
:service
)
{
described_class
.
new
(
project
,
user
,
opts
)
}
before
do
project
.
add_developer
(
user
)
end
describe
'initialization'
do
context
'author commit info'
do
it
'does not raise error if user is nil'
do
service
=
described_class
.
new
(
project
,
nil
,
opts
)
expect
(
service
.
instance_variable_get
(
:@author_email
)).
to
be_nil
expect
(
service
.
instance_variable_get
(
:@author_name
)).
to
be_nil
end
it
'fills file_path from the repository uploads folder'
do
expect
(
service
.
instance_variable_get
(
:@file_path
)).
to
match
(
file_path_regex
)
end
context
'when no author info provided'
do
it
'fills author_email and author_name from current_user info'
do
expect
(
service
.
instance_variable_get
(
:@author_email
)).
to
eq
user
.
email
expect
(
service
.
instance_variable_get
(
:@author_name
)).
to
eq
user
.
name
end
end
context
'when author info provided'
do
let
(
:author_email
)
{
'author_email'
}
let
(
:author_name
)
{
'author_name'
}
let
(
:opts
)
{
file_opts
.
merge
(
author_email:
author_email
,
author_name:
author_name
)
}
it
'fills author_email and author_name from params'
do
expect
(
service
.
instance_variable_get
(
:@author_email
)).
to
eq
author_email
expect
(
service
.
instance_variable_get
(
:@author_name
)).
to
eq
author_name
end
end
end
context
'commit message'
do
context
'when no commit message provided'
do
it
'sets a default commit message'
do
expect
(
service
.
instance_variable_get
(
:@commit_message
)).
to
eq
"Upload attachment
#{
opts
[
:file_name
]
}
"
end
end
context
'when commit message provided'
do
let
(
:commit_message
)
{
'whatever'
}
let
(
:opts
)
{
file_opts
.
merge
(
commit_message:
commit_message
)
}
it
'use the commit message from params'
do
expect
(
service
.
instance_variable_get
(
:@commit_message
)).
to
eq
commit_message
end
end
end
context
'branch name'
do
context
'when no branch provided'
do
it
'sets the branch from the wiki default_branch'
do
expect
(
service
.
instance_variable_get
(
:@branch_name
)).
to
eq
project
.
wiki
.
default_branch
end
end
context
'when branch provided'
do
let
(
:branch_name
)
{
'whatever'
}
let
(
:opts
)
{
file_opts
.
merge
(
branch_name:
branch_name
)
}
it
'use the commit message from params'
do
expect
(
service
.
instance_variable_get
(
:@branch_name
)).
to
eq
branch_name
end
end
end
end
describe
'validations'
do
context
'when file_name'
do
context
'is not present'
do
let
(
:file_name
)
{
nil
}
it
'returns error'
do
result
=
service
.
execute
expect
(
result
[
:status
]).
to
eq
:error
expect
(
result
[
:message
]).
to
eq
'The file name cannot be empty'
end
end
context
'length'
do
context
'is bigger than 255'
do
let
(
:file_name
)
{
"
#{
'0'
*
256
}
.jpg"
}
it
'truncates file name'
do
result
=
service
.
execute
expect
(
result
[
:status
]).
to
eq
:success
expect
(
result
[
:result
][
:file_name
].
length
).
to
eq
255
expect
(
result
[
:result
][
:file_name
]).
to
match
(
/0{251}\.jpg/
)
end
end
context
'is less or equal to 255 does not return error'
do
let
(
:file_name
)
{
'0'
*
255
}
it
'does not return error'
do
result
=
service
.
execute
expect
(
result
[
:status
]).
to
eq
:success
end
end
end
end
context
'when user'
do
shared_examples
'wiki attachment user validations'
do
it
'returns error'
do
result
=
described_class
.
new
(
project
,
user2
,
opts
).
execute
expect
(
result
[
:status
]).
to
eq
:error
expect
(
result
[
:message
]).
to
eq
'You are not allowed to push to the wiki'
end
end
context
'does not have permission'
do
let
(
:user2
)
{
create
(
:user
)
}
it_behaves_like
'wiki attachment user validations'
end
context
'is nil'
do
let
(
:user2
)
{
nil
}
it_behaves_like
'wiki attachment user validations'
end
end
end
describe
'#execute'
do
let
(
:wiki
)
{
project
.
wiki
}
subject
(
:service_execute
)
{
service
.
execute
[
:result
]
}
context
'creates branch if it does not exists'
do
let
(
:branch_name
)
{
'new_branch'
}
let
(
:opts
)
{
file_opts
.
merge
(
branch_name:
branch_name
)
}
it
do
expect
(
wiki
.
repository
.
branches
).
to
be_empty
expect
{
service
.
execute
}.
to
change
{
wiki
.
repository
.
branches
.
count
}.
by
(
1
)
expect
(
wiki
.
repository
.
branches
.
first
.
name
).
to
eq
branch_name
end
end
it
'adds file to the repository'
do
expect
(
wiki
.
repository
.
ls_files
(
'HEAD'
)).
to
be_empty
service
.
execute
files
=
wiki
.
repository
.
ls_files
(
'HEAD'
)
expect
(
files
.
count
).
to
eq
1
expect
(
files
.
first
).
to
match
(
file_path_regex
)
end
context
'returns'
do
before
do
allow
(
SecureRandom
).
to
receive
(
:hex
).
and_return
(
'fixed_hex'
)
service_execute
end
it
'returns the file name'
do
expect
(
service_execute
[
:file_name
]).
to
eq
file_name
end
it
'returns the path where file was stored'
do
expect
(
service_execute
[
:file_path
]).
to
eq
'uploads/fixed_hex/filename.txt'
end
it
'returns the branch where the file was pushed'
do
expect
(
service_execute
[
:branch
]).
to
eq
wiki
.
default_branch
end
it
'returns the commit id'
do
expect
(
service_execute
[
:commit
]).
not_to
be_empty
end
end
end
end
spec/support/shared_examples/wiki_file_attachments_examples.rb
0 → 100644
View file @
f9475e29
# frozen_string_literal: true
# Requires a context containing:
# project
shared_examples
'wiki file attachments'
do
include
DropzoneHelper
context
'uploading attachments'
,
:js
do
let
(
:wiki
)
{
project
.
wiki
}
def
attach_with_dropzone
(
wait
=
false
)
dropzone_file
([
Rails
.
root
.
join
(
'spec'
,
'fixtures'
,
'dk.png'
)],
0
,
wait
)
end
context
'before uploading'
do
it
'shows "Attach a file" button'
do
expect
(
page
).
to
have_button
(
'Attach a file'
)
expect
(
page
).
not_to
have_selector
(
'.uploading-progress-container'
,
visible:
true
)
end
end
context
'uploading is in progress'
do
it
'cancels uploading on clicking to "Cancel" button'
do
slow_requests
do
attach_with_dropzone
click_button
'Cancel'
end
expect
(
page
).
to
have_button
(
'Attach a file'
)
expect
(
page
).
not_to
have_button
(
'Cancel'
)
expect
(
page
).
not_to
have_selector
(
'.uploading-progress-container'
,
visible:
true
)
end
it
'shows "Attaching a file" message on uploading 1 file'
do
slow_requests
do
attach_with_dropzone
expect
(
page
).
to
have_selector
(
'.attaching-file-message'
,
visible:
true
,
text:
'Attaching a file -'
)
end
end
end
context
'uploading is complete'
do
it
'shows "Attach a file" button on uploading complete'
do
attach_with_dropzone
wait_for_requests
expect
(
page
).
to
have_button
(
'Attach a file'
)
expect
(
page
).
not_to
have_selector
(
'.uploading-progress-container'
,
visible:
true
)
end
it
'the markdown link is added to the page'
do
fill_in
(
:wiki_content
,
with:
''
)
attach_with_dropzone
(
true
)
wait_for_requests
expect
(
page
.
find
(
'#wiki_content'
).
value
)
.
to
match
(
%r{
\!\[
dk
\]\(
uploads/
\h
{32}/dk
\.
png
\)
$}
)
end
it
'the links point to the wiki root url'
do
attach_with_dropzone
(
true
)
wait_for_requests
find
(
'.js-md-preview-button'
).
click
file_path
=
page
.
find
(
'input[name="files[]"]'
,
visible: :hidden
).
value
link
=
page
.
find
(
'a.no-attachment-icon'
)[
'href'
]
img_link
=
page
.
find
(
'a.no-attachment-icon img'
)[
'src'
]
expect
(
link
).
to
eq
img_link
expect
(
URI
.
parse
(
link
).
path
).
to
eq
File
.
join
(
wiki
.
wiki_base_path
,
file_path
)
end
it
'the file has been added to the wiki repository'
do
expect
do
attach_with_dropzone
(
true
)
wait_for_requests
end
.
to
change
{
wiki
.
repository
.
ls_files
(
'HEAD'
).
count
}.
by
(
1
)
file_path
=
page
.
find
(
'input[name="files[]"]'
,
visible: :hidden
).
value
expect
(
wiki
.
find_file
(
file_path
,
'HEAD'
).
path
).
not_to
be_nil
end
end
end
end
spec/uploaders/uploader_helper_spec.rb
View file @
f9475e29
...
...
@@ -11,27 +11,10 @@ describe UploaderHelper do
example_uploader
.
new
end
def
upload_fixture
(
filename
)
fixture_file_upload
(
File
.
join
(
'spec'
,
'fixtures'
,
filename
))
end
describe
'#image_or_video?'
do
it
'returns true for an image file'
do
uploader
.
store!
(
upload_fixture
(
'dk.png'
))
expect
(
uploader
).
to
be_image_or_video
end
it
'it returns true for a video file'
do
uploader
.
store!
(
upload_fixture
(
'video_sample.mp4'
))
expect
(
uploader
).
to
be_image_or_video
end
it
'returns false for other extensions'
do
uploader
.
store!
(
upload_fixture
(
'doc_sample.txt'
))
expect
(
uploader
).
not_to
be_image_or_video
describe
'#extension_match?'
do
it
'returns false if file does not exists'
do
expect
(
uploader
.
file
).
to
be_nil
expect
(
uploader
.
send
(
:extension_match?
,
'jpg'
)).
to
eq
false
end
end
end
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