Commit e05a86ce authored by Nick Thomas's avatar Nick Thomas

Allow all personal snippets to be accessed by API

Previously, you could only access personal snippets in the API if you
had authored them. The documentation doesn't state that this is the
case, and it's quite surprising.
parent 42d3117f
...@@ -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