Skip to content
Snippets Groups Projects
Commit 2b3fc5e6 authored by Douwe Maan's avatar Douwe Maan
Browse files

Add download button to project snippets

parent 54040ce0
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -5,10 +5,12 @@ module SnippetsActions
end
 
def raw
disposition = params[:inline] == 'false' ? 'attachment' : 'inline'
send_data(
convert_line_endings(@snippet.content),
type: 'text/plain; charset=utf-8',
disposition: 'inline',
disposition: disposition,
filename: @snippet.sanitized_file_name
)
end
Loading
Loading
Loading
Loading
@@ -5,10 +5,10 @@ class SnippetsController < ApplicationController
include MarkdownPreview
include RendersBlob
 
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :download]
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
 
# Allow read snippet
before_action :authorize_read_snippet!, only: [:show, :raw, :download]
before_action :authorize_read_snippet!, only: [:show, :raw]
 
# Allow modify snippet
before_action :authorize_update_snippet!, only: [:edit, :update]
Loading
Loading
@@ -16,7 +16,7 @@ class SnippetsController < ApplicationController
# Allow destroy snippet
before_action :authorize_admin_snippet!, only: [:destroy]
 
skip_before_action :authenticate_user!, only: [:index, :show, :raw, :download]
skip_before_action :authenticate_user!, only: [:index, :show, :raw]
 
layout 'snippets'
respond_to :html
Loading
Loading
@@ -83,14 +83,6 @@ class SnippetsController < ApplicationController
redirect_to snippets_path
end
 
def download
send_data(
convert_line_endings(@snippet.content),
type: 'text/plain; charset=utf-8',
filename: @snippet.sanitized_file_name
)
end
def preview_markdown
render_markdown_preview(params[:text], skip_project_check: true)
end
Loading
Loading
Loading
Loading
@@ -118,15 +118,15 @@ module BlobHelper
icon("#{file_type_icon_class('file', mode, name)} fw")
end
 
def blob_raw_url
def blob_raw_url(params = {})
if @snippet
if @snippet.project_id
raw_namespace_project_snippet_path(@project.namespace, @project, @snippet)
raw_namespace_project_snippet_path(@project.namespace, @project, @snippet, params)
else
raw_snippet_path(@snippet)
raw_snippet_path(@snippet, params)
end
elsif @blob
namespace_project_raw_path(@project.namespace, @project, @id)
namespace_project_raw_path(@project.namespace, @project, @id, params)
end
end
 
Loading
Loading
Loading
Loading
@@ -18,7 +18,6 @@
= copy_blob_source_button(blob)
= open_raw_blob_button(blob)
 
- if defined?(download_path) && download_path
= link_to icon('download'), download_path, class: "btn btn-sm has-tooltip", title: 'Download', data: { container: 'body' }
= link_to icon('download'), blob_raw_url(inline: false), target: '_blank', class: "btn btn-sm has-tooltip", title: 'Download', data: { container: 'body' }
 
= render 'projects/blob/content', blob: blob
Loading
Loading
@@ -3,7 +3,7 @@
= render 'shared/snippets/header'
 
%article.file-holder.snippet-file-content
= render 'shared/snippets/blob', download_path: download_snippet_path(@snippet)
= render 'shared/snippets/blob'
 
.row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
---
title: Add download button to project snippets
merge_request:
author:
Loading
Loading
@@ -44,7 +44,7 @@ constraints(ProjectUrlConstrainer.new) do
 
resources :snippets, concerns: :awardable, constraints: { id: /\d+/ } do
member do
get 'raw'
get :raw
post :mark_as_spam
end
end
Loading
Loading
resources :snippets, concerns: :awardable do
member do
get 'raw'
get 'download'
get :raw
post :mark_as_spam
post :preview_markdown
end
Loading
Loading
Loading
Loading
@@ -350,144 +350,138 @@ describe SnippetsController do
end
end
 
%w(raw download).each do |action|
describe "GET #{action}" do
context 'when the personal snippet is private' do
let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
describe "GET #raw" do
context 'when the personal snippet is private' do
let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
 
context 'when signed in' do
before do
sign_in(user)
end
context 'when signed in' do
before do
sign_in(user)
end
 
context 'when signed in user is not the author' do
let(:other_author) { create(:author) }
let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_author) }
context 'when signed in user is not the author' do
let(:other_author) { create(:author) }
let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_author) }
 
it 'responds with status 404' do
get action, id: other_personal_snippet.to_param
it 'responds with status 404' do
get :raw, id: other_personal_snippet.to_param
 
expect(response).to have_http_status(404)
end
expect(response).to have_http_status(404)
end
end
 
context 'when signed in user is the author' do
before { get action, id: personal_snippet.to_param }
context 'when signed in user is the author' do
before { get :raw, id: personal_snippet.to_param }
 
it 'responds with status 200' do
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_http_status(200)
end
it 'responds with status 200' do
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_http_status(200)
end
 
it 'has expected headers' do
expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
it 'has expected headers' do
expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
 
if action == :download
expect(response.header['Content-Disposition']).to match(/attachment/)
elsif action == :raw
expect(response.header['Content-Disposition']).to match(/inline/)
end
end
expect(response.header['Content-Disposition']).to match(/inline/)
end
end
end
 
context 'when not signed in' do
it 'redirects to the sign in page' do
get action, id: personal_snippet.to_param
context 'when not signed in' do
it 'redirects to the sign in page' do
get :raw, id: personal_snippet.to_param
 
expect(response).to redirect_to(new_user_session_path)
end
expect(response).to redirect_to(new_user_session_path)
end
end
end
 
context 'when the personal snippet is internal' do
let(:personal_snippet) { create(:personal_snippet, :internal, author: user) }
context 'when the personal snippet is internal' do
let(:personal_snippet) { create(:personal_snippet, :internal, author: user) }
 
context 'when signed in' do
before do
sign_in(user)
end
context 'when signed in' do
before do
sign_in(user)
end
 
it 'responds with status 200' do
get action, id: personal_snippet.to_param
it 'responds with status 200' do
get :raw, id: personal_snippet.to_param
 
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_http_status(200)
end
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_http_status(200)
end
end
 
context 'when not signed in' do
it 'redirects to the sign in page' do
get action, id: personal_snippet.to_param
context 'when not signed in' do
it 'redirects to the sign in page' do
get :raw, id: personal_snippet.to_param
 
expect(response).to redirect_to(new_user_session_path)
end
expect(response).to redirect_to(new_user_session_path)
end
end
end
 
context 'when the personal snippet is public' do
let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
context 'when the personal snippet is public' do
let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
 
context 'when signed in' do
before do
sign_in(user)
end
context 'when signed in' do
before do
sign_in(user)
end
 
it 'responds with status 200' do
get action, id: personal_snippet.to_param
it 'responds with status 200' do
get :raw, id: personal_snippet.to_param
 
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_http_status(200)
end
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_http_status(200)
end
 
context 'CRLF line ending' do
let(:personal_snippet) do
create(:personal_snippet, :public, author: user, content: "first line\r\nsecond line\r\nthird line")
end
context 'CRLF line ending' do
let(:personal_snippet) do
create(:personal_snippet, :public, author: user, content: "first line\r\nsecond line\r\nthird line")
end
 
it 'returns LF line endings by default' do
get action, id: personal_snippet.to_param
it 'returns LF line endings by default' do
get :raw, id: personal_snippet.to_param
 
expect(response.body).to eq("first line\nsecond line\nthird line")
end
expect(response.body).to eq("first line\nsecond line\nthird line")
end
 
it 'does not convert line endings when parameter present' do
get action, id: personal_snippet.to_param, line_ending: :raw
it 'does not convert line endings when parameter present' do
get :raw, id: personal_snippet.to_param, line_ending: :raw
 
expect(response.body).to eq("first line\r\nsecond line\r\nthird line")
end
expect(response.body).to eq("first line\r\nsecond line\r\nthird line")
end
end
end
 
context 'when not signed in' do
it 'responds with status 200' do
get action, id: personal_snippet.to_param
context 'when not signed in' do
it 'responds with status 200' do
get :raw, id: personal_snippet.to_param
 
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_http_status(200)
end
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_http_status(200)
end
end
end
 
context 'when the personal snippet does not exist' do
context 'when signed in' do
before do
sign_in(user)
end
context 'when the personal snippet does not exist' do
context 'when signed in' do
before do
sign_in(user)
end
 
it 'responds with status 404' do
get action, id: 'doesntexist'
it 'responds with status 404' do
get :raw, id: 'doesntexist'
 
expect(response).to have_http_status(404)
end
expect(response).to have_http_status(404)
end
end
 
context 'when not signed in' do
it 'responds with status 404' do
get action, id: 'doesntexist'
context 'when not signed in' do
it 'responds with status 404' do
get :raw, id: 'doesntexist'
 
expect(response).to have_http_status(404)
end
expect(response).to have_http_status(404)
end
end
end
Loading
Loading
Loading
Loading
@@ -30,6 +30,12 @@ feature 'Project snippet', :js, feature: true do
 
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
# shows a raw button
expect(page).to have_link('Open raw')
# shows a download button
expect(page).to have_link('Download')
end
end
end
Loading
Loading
@@ -59,6 +65,12 @@ feature 'Project snippet', :js, feature: true do
 
# shows a disabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
# shows a raw button
expect(page).to have_link('Open raw')
# shows a download button
expect(page).to have_link('Download')
end
end
 
Loading
Loading
Loading
Loading
@@ -24,6 +24,12 @@ feature 'Snippet', :js, feature: true do
 
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
# shows a raw button
expect(page).to have_link('Open raw')
# shows a download button
expect(page).to have_link('Download')
end
end
end
Loading
Loading
@@ -53,6 +59,12 @@ feature 'Snippet', :js, feature: true do
 
# shows a disabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
# shows a raw button
expect(page).to have_link('Open raw')
# shows a download button
expect(page).to have_link('Download')
end
end
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment