Commit 12818c20 authored by Robert Speicher's avatar Robert Speicher

Merge branch '41888-access-personal-snippets-by-api' into 'master'

Allow all snippets to be accessed by API

Closes #41888

See merge request gitlab-org/gitlab-ce!25772
parents f944971b e05a86ce
...@@ -69,6 +69,8 @@ class SnippetsFinder < UnionFinder ...@@ -69,6 +69,8 @@ class SnippetsFinder < UnionFinder
base.with_optional_visibility(visibility_from_scope).fresh base.with_optional_visibility(visibility_from_scope).fresh
end end
private
# Produces a query that retrieves snippets from multiple projects. # Produces a query that retrieves snippets from multiple projects.
# #
# The resulting query will, depending on the user's permissions, include the # The resulting query will, depending on the user's permissions, include the
......
---
title: Allow all snippets to be accessed by API
merge_request: 25772
author:
type: added
...@@ -16,6 +16,10 @@ module API ...@@ -16,6 +16,10 @@ module API
def public_snippets def public_snippets
SnippetsFinder.new(current_user, scope: :are_public).execute SnippetsFinder.new(current_user, scope: :are_public).execute
end end
def snippets
SnippetsFinder.new(current_user).execute
end
end end
desc 'Get a snippets list for authenticated user' do desc 'Get a snippets list for authenticated user' do
...@@ -48,7 +52,10 @@ module API ...@@ -48,7 +52,10 @@ module API
requires :id, type: Integer, desc: 'The ID of a snippet' requires :id, type: Integer, desc: 'The ID of a snippet'
end end
get ':id' do get ':id' do
snippet = snippets_for_current_user.find(params[:id]) snippet = snippets.find_by_id(params[:id])
break not_found!('Snippet') unless snippet
present snippet, with: Entities::PersonalSnippet present snippet, with: Entities::PersonalSnippet
end end
...@@ -94,9 +101,8 @@ module API ...@@ -94,9 +101,8 @@ module API
desc: 'The visibility of the snippet' desc: 'The visibility of the snippet'
at_least_one_of :title, :file_name, :content, :visibility at_least_one_of :title, :file_name, :content, :visibility
end end
# rubocop: disable CodeReuse/ActiveRecord
put ':id' do put ':id' do
snippet = snippets_for_current_user.find_by(id: params.delete(:id)) snippet = snippets_for_current_user.find_by_id(params.delete(:id))
break not_found!('Snippet') unless snippet break not_found!('Snippet') unless snippet
authorize! :update_personal_snippet, snippet authorize! :update_personal_snippet, snippet
...@@ -113,7 +119,6 @@ module API ...@@ -113,7 +119,6 @@ module API
render_validation_error!(snippet) render_validation_error!(snippet)
end end
end end
# rubocop: enable CodeReuse/ActiveRecord
desc 'Remove snippet' do desc 'Remove snippet' do
detail 'This feature was introduced in GitLab 8.15.' detail 'This feature was introduced in GitLab 8.15.'
...@@ -122,16 +127,14 @@ module API ...@@ -122,16 +127,14 @@ module API
params do params do
requires :id, type: Integer, desc: 'The ID of a snippet' requires :id, type: Integer, desc: 'The ID of a snippet'
end end
# rubocop: disable CodeReuse/ActiveRecord
delete ':id' do delete ':id' do
snippet = snippets_for_current_user.find_by(id: params.delete(:id)) snippet = snippets_for_current_user.find_by_id(params.delete(:id))
break not_found!('Snippet') unless snippet break not_found!('Snippet') unless snippet
authorize! :destroy_personal_snippet, snippet authorize! :destroy_personal_snippet, snippet
destroy_conditionally!(snippet) destroy_conditionally!(snippet)
end end
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get a raw snippet' do desc 'Get a raw snippet' do
detail 'This feature was introduced in GitLab 8.15.' detail 'This feature was introduced in GitLab 8.15.'
...@@ -139,9 +142,8 @@ module API ...@@ -139,9 +142,8 @@ module API
params do params do
requires :id, type: Integer, desc: 'The ID of a snippet' requires :id, type: Integer, desc: 'The ID of a snippet'
end end
# rubocop: disable CodeReuse/ActiveRecord
get ":id/raw" do get ":id/raw" do
snippet = snippets_for_current_user.find_by(id: params.delete(:id)) snippet = snippets.find_by_id(params.delete(:id))
break not_found!('Snippet') unless snippet break not_found!('Snippet') unless snippet
env['api.format'] = :txt env['api.format'] = :txt
...@@ -149,7 +151,6 @@ module API ...@@ -149,7 +151,6 @@ module API
header['Content-Disposition'] = 'attachment' header['Content-Disposition'] = 'attachment'
present snippet.content present snippet.content
end end
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get the user agent details for a snippet' do desc 'Get the user agent details for a snippet' do
success Entities::UserAgentDetail success Entities::UserAgentDetail
...@@ -157,17 +158,15 @@ module API ...@@ -157,17 +158,15 @@ module API
params do params do
requires :id, type: Integer, desc: 'The ID of a snippet' requires :id, type: Integer, desc: 'The ID of a snippet'
end end
# rubocop: disable CodeReuse/ActiveRecord
get ":id/user_agent_detail" do get ":id/user_agent_detail" do
authenticated_as_admin! authenticated_as_admin!
snippet = Snippet.find_by!(id: params[:id]) snippet = Snippet.find_by_id!(params[:id])
break not_found!('UserAgentDetail') unless snippet.user_agent_detail break not_found!('UserAgentDetail') unless snippet.user_agent_detail
present snippet.user_agent_detail, with: Entities::UserAgentDetail present snippet.user_agent_detail, with: Entities::UserAgentDetail
end end
# rubocop: enable CodeReuse/ActiveRecord
end end
end end
end end
...@@ -84,10 +84,17 @@ describe API::Snippets do ...@@ -84,10 +84,17 @@ describe API::Snippets do
end end
describe 'GET /snippets/:id/raw' do describe 'GET /snippets/:id/raw' do
let(:snippet) { create(:personal_snippet, author: user) } set(:author) { create(:user) }
set(:snippet) { create(:personal_snippet, :private, author: author) }
it 'requires authentication' do
get api("/snippets/#{snippet.id}", nil)
expect(response).to have_gitlab_http_status(401)
end
it 'returns raw text' do it 'returns raw text' do
get api("/snippets/#{snippet.id}/raw", user) get api("/snippets/#{snippet.id}/raw", author)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response.content_type).to eq 'text/plain' expect(response.content_type).to eq 'text/plain'
...@@ -95,38 +102,83 @@ describe API::Snippets do ...@@ -95,38 +102,83 @@ describe API::Snippets do
end end
it 'forces attachment content disposition' do it 'forces attachment content disposition' do
get api("/snippets/#{snippet.id}/raw", user) get api("/snippets/#{snippet.id}/raw", author)
expect(headers['Content-Disposition']).to match(/^attachment/) expect(headers['Content-Disposition']).to match(/^attachment/)
end end
it 'returns 404 for invalid snippet id' do it 'returns 404 for invalid snippet id' do
get api("/snippets/1234/raw", user) snippet.destroy
get api("/snippets/#{snippet.id}/raw", author)
expect(response).to have_gitlab_http_status(404) expect(response).to have_gitlab_http_status(404)
expect(json_response['message']).to eq('404 Snippet Not Found') expect(json_response['message']).to eq('404 Snippet Not Found')
end end
it 'hides private snippets from ordinary users' do
get api("/snippets/#{snippet.id}/raw", user)
expect(response).to have_gitlab_http_status(404)
end
it 'shows internal snippets to ordinary users' do
internal_snippet = create(:personal_snippet, :internal, author: author)
get api("/snippets/#{internal_snippet.id}/raw", user)
expect(response).to have_gitlab_http_status(200)
end
end end
describe 'GET /snippets/:id' do describe 'GET /snippets/:id' do
let(:snippet) { create(:personal_snippet, author: user) } set(:admin) { create(:user, :admin) }
set(:author) { create(:user) }
set(:private_snippet) { create(:personal_snippet, :private, author: author) }
set(:internal_snippet) { create(:personal_snippet, :internal, author: author) }
it 'requires authentication' do
get api("/snippets/#{private_snippet.id}", nil)
expect(response).to have_gitlab_http_status(401)
end
it 'returns snippet json' do it 'returns snippet json' do
get api("/snippets/#{snippet.id}", user) get api("/snippets/#{private_snippet.id}", author)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(json_response['title']).to eq(snippet.title) expect(json_response['title']).to eq(private_snippet.title)
expect(json_response['description']).to eq(snippet.description) expect(json_response['description']).to eq(private_snippet.description)
expect(json_response['file_name']).to eq(snippet.file_name) expect(json_response['file_name']).to eq(private_snippet.file_name)
expect(json_response['visibility']).to eq(snippet.visibility) expect(json_response['visibility']).to eq(private_snippet.visibility)
end
it 'shows private snippets to an admin' do
get api("/snippets/#{private_snippet.id}", admin)
expect(response).to have_gitlab_http_status(200)
end
it 'hides private snippets from an ordinary user' do
get api("/snippets/#{private_snippet.id}", user)
expect(response).to have_gitlab_http_status(404)
end
it 'shows internal snippets to an ordinary user' do
get api("/snippets/#{internal_snippet.id}", user)
expect(response).to have_gitlab_http_status(200)
end end
it 'returns 404 for invalid snippet id' do it 'returns 404 for invalid snippet id' do
get api("/snippets/1234", user) private_snippet.destroy
get api("/snippets/#{private_snippet.id}", admin)
expect(response).to have_gitlab_http_status(404) expect(response).to have_gitlab_http_status(404)
expect(json_response['message']).to eq('404 Not found') expect(json_response['message']).to eq('404 Snippet Not Found')
end end
end end
......
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