Commit 20985616 authored by Toon Claes's avatar Toon Claes

Expose Snippet VisibilityLevel as String

parent ed8f13c7
...@@ -5,15 +5,15 @@ ...@@ -5,15 +5,15 @@
### Snippet visibility level ### Snippet visibility level
Snippets in GitLab can be either private, internal, or public. Snippets in GitLab can be either private, internal, or public.
You can set it with the `visibility_level` field in the snippet. You can set it with the `visibility` field in the snippet.
Constants for snippet visibility levels are: Constants for snippet visibility levels are:
| Visibility | Visibility level | Description | | Visibility | Description |
| ---------- | ---------------- | ----------- | | ---------- | ----------- |
| Private | `0` | The snippet is visible only to the snippet creator | | `private` | The snippet is visible only to the snippet creator |
| Internal | `10` | The snippet is visible for any logged in user | | `internal` | The snippet is visible for any logged in user |
| Public | `20` | The snippet can be accessed without any authentication | | `public` | The snippet can be accessed without any authentication |
## List snippets ## List snippets
...@@ -78,11 +78,11 @@ Parameters: ...@@ -78,11 +78,11 @@ Parameters:
| `title` | String | yes | The title of a snippet | | `title` | String | yes | The title of a snippet |
| `file_name` | String | yes | The name of a snippet file | | `file_name` | String | yes | The name of a snippet file |
| `content` | String | yes | The content of a snippet | | `content` | String | yes | The content of a snippet |
| `visibility_level` | Integer | yes | The snippet's visibility | | `visibility` | String | yes | The snippet's visibility |
``` bash ``` bash
curl --request POST --data '{"title": "This is a snippet", "content": "Hello world", "file_name": "test.txt", "visibility_level": 10 }' --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/snippets curl --request POST --data '{"title": "This is a snippet", "content": "Hello world", "file_name": "test.txt", "visibility": "internal" }' --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/snippets
``` ```
Example response: Example response:
...@@ -123,7 +123,7 @@ Parameters: ...@@ -123,7 +123,7 @@ Parameters:
| `title` | String | no | The title of a snippet | | `title` | String | no | The title of a snippet |
| `file_name` | String | no | The name of a snippet file | | `file_name` | String | no | The name of a snippet file |
| `content` | String | no | The content of a snippet | | `content` | String | no | The content of a snippet |
| `visibility_level` | Integer | no | The snippet's visibility | | `visibility` | String | no | The snippet's visibility |
``` bash ``` bash
...@@ -229,4 +229,3 @@ Example response: ...@@ -229,4 +229,3 @@ Example response:
} }
] ]
``` ```
...@@ -26,6 +26,7 @@ module API ...@@ -26,6 +26,7 @@ module API
mount ::API::V3::Repositories mount ::API::V3::Repositories
mount ::API::V3::Runners mount ::API::V3::Runners
mount ::API::V3::Services mount ::API::V3::Services
mount ::API::V3::Snippets
mount ::API::V3::Subscriptions mount ::API::V3::Subscriptions
mount ::API::V3::SystemHooks mount ::API::V3::SystemHooks
mount ::API::V3::Tags mount ::API::V3::Tags
......
...@@ -58,13 +58,13 @@ module API ...@@ -58,13 +58,13 @@ module API
requires :title, type: String, desc: 'The title of a snippet' requires :title, type: String, desc: 'The title of a snippet'
requires :file_name, type: String, desc: 'The name of a snippet file' requires :file_name, type: String, desc: 'The name of a snippet file'
requires :content, type: String, desc: 'The content of a snippet' requires :content, type: String, desc: 'The content of a snippet'
optional :visibility_level, type: Integer, optional :visibility, type: String,
values: Gitlab::VisibilityLevel.values, values: Gitlab::VisibilityLevel.string_values,
default: Gitlab::VisibilityLevel::INTERNAL, default: 'internal',
desc: 'The visibility level of the snippet' desc: 'The visibility of the snippet'
end end
post do post do
attrs = declared_params(include_missing: false).merge(request: request, api: true) attrs = map_visibility_level(declared_params(include_missing: false)).merge(request: request, api: true)
snippet = CreateSnippetService.new(nil, current_user, attrs).execute snippet = CreateSnippetService.new(nil, current_user, attrs).execute
render_spam_error! if snippet.spam? render_spam_error! if snippet.spam?
...@@ -85,17 +85,17 @@ module API ...@@ -85,17 +85,17 @@ module API
optional :title, type: String, desc: 'The title of a snippet' optional :title, type: String, desc: 'The title of a snippet'
optional :file_name, type: String, desc: 'The name of a snippet file' optional :file_name, type: String, desc: 'The name of a snippet file'
optional :content, type: String, desc: 'The content of a snippet' optional :content, type: String, desc: 'The content of a snippet'
optional :visibility_level, type: Integer, optional :visibility, type: String,
values: Gitlab::VisibilityLevel.values, values: Gitlab::VisibilityLevel.string_values,
desc: 'The visibility level of the snippet' desc: 'The visibility of the snippet'
at_least_one_of :title, :file_name, :content, :visibility_level at_least_one_of :title, :file_name, :content, :visibility
end end
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))
return not_found!('Snippet') unless snippet return not_found!('Snippet') unless snippet
authorize! :update_personal_snippet, snippet authorize! :update_personal_snippet, snippet
attrs = declared_params(include_missing: false).merge(request: request, api: true) attrs = map_visibility_level(declared_params(include_missing: false).merge(request: request, api: true))
UpdateSnippetService.new(nil, current_user, snippet, attrs).execute UpdateSnippetService.new(nil, current_user, snippet, attrs).execute
......
module API
module V3
class Snippets < Grape::API
include PaginationParams
before { authenticate! }
resource :snippets do
helpers do
def snippets_for_current_user
SnippetsFinder.new.execute(current_user, filter: :by_user, user: current_user)
end
def public_snippets
SnippetsFinder.new.execute(current_user, filter: :public)
end
end
desc 'Get a snippets list for authenticated user' do
detail 'This feature was introduced in GitLab 8.15.'
success ::API::Entities::PersonalSnippet
end
params do
use :pagination
end
get do
present paginate(snippets_for_current_user), with: ::API::Entities::PersonalSnippet
end
desc 'List all public snippets current_user has access to' do
detail 'This feature was introduced in GitLab 8.15.'
success ::API::Entities::PersonalSnippet
end
params do
use :pagination
end
get 'public' do
present paginate(public_snippets), with: ::API::Entities::PersonalSnippet
end
desc 'Get a single snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success ::API::Entities::PersonalSnippet
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
end
get ':id' do
snippet = snippets_for_current_user.find(params[:id])
present snippet, with: ::API::Entities::PersonalSnippet
end
desc 'Create new snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success ::API::Entities::PersonalSnippet
end
params do
requires :title, type: String, desc: 'The title of a snippet'
requires :file_name, type: String, desc: 'The name of a snippet file'
requires :content, type: String, desc: 'The content of a snippet'
optional :visibility_level, type: Integer,
values: Gitlab::VisibilityLevel.values,
default: Gitlab::VisibilityLevel::INTERNAL,
desc: 'The visibility level of the snippet'
end
post do
attrs = declared_params(include_missing: false).merge(request: request, api: true)
snippet = CreateSnippetService.new(nil, current_user, attrs).execute
if snippet.persisted?
present snippet, with: ::API::Entities::PersonalSnippet
else
render_validation_error!(snippet)
end
end
desc 'Update an existing snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success ::API::Entities::PersonalSnippet
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
optional :title, type: String, desc: 'The title of a snippet'
optional :file_name, type: String, desc: 'The name of a snippet file'
optional :content, type: String, desc: 'The content of a snippet'
optional :visibility_level, type: Integer,
values: Gitlab::VisibilityLevel.values,
desc: 'The visibility level of the snippet'
at_least_one_of :title, :file_name, :content, :visibility_level
end
put ':id' do
snippet = snippets_for_current_user.find_by(id: params.delete(:id))
return not_found!('Snippet') unless snippet
authorize! :update_personal_snippet, snippet
attrs = declared_params(include_missing: false)
UpdateSnippetService.new(nil, current_user, snippet, attrs).execute
if snippet.persisted?
present snippet, with: ::API::Entities::PersonalSnippet
else
render_validation_error!(snippet)
end
end
desc 'Remove snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success ::API::Entities::PersonalSnippet
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
end
delete ':id' do
snippet = snippets_for_current_user.find_by(id: params.delete(:id))
return not_found!('Snippet') unless snippet
authorize! :destroy_personal_snippet, snippet
snippet.destroy
no_content!
end
desc 'Get a raw snippet' do
detail 'This feature was introduced in GitLab 8.15.'
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
end
get ":id/raw" do
snippet = snippets_for_current_user.find_by(id: params.delete(:id))
return not_found!('Snippet') unless snippet
env['api.format'] = :txt
content_type 'text/plain'
present snippet.content
end
end
end
end
end
...@@ -87,7 +87,7 @@ describe API::Snippets, api: true do ...@@ -87,7 +87,7 @@ describe API::Snippets, api: true do
title: 'Test Title', title: 'Test Title',
file_name: 'test.rb', file_name: 'test.rb',
content: 'puts "hello world"', content: 'puts "hello world"',
visibility_level: Snippet::PUBLIC visibility: 'public'
} }
end end
...@@ -120,14 +120,14 @@ describe API::Snippets, api: true do ...@@ -120,14 +120,14 @@ describe API::Snippets, api: true do
context 'when the snippet is private' do context 'when the snippet is private' do
it 'creates the snippet' do it 'creates the snippet' do
expect { create_snippet(visibility_level: Snippet::PRIVATE) }. expect { create_snippet(visibility: 'private') }.
to change { Snippet.count }.by(1) to change { Snippet.count }.by(1)
end end
end end
context 'when the snippet is public' do context 'when the snippet is public' do
it 'rejects the shippet' do it 'rejects the shippet' do
expect { create_snippet(visibility_level: Snippet::PUBLIC) }. expect { create_snippet(visibility: 'public') }.
not_to change { Snippet.count } not_to change { Snippet.count }
expect(response).to have_http_status(400) expect(response).to have_http_status(400)
...@@ -135,7 +135,7 @@ describe API::Snippets, api: true do ...@@ -135,7 +135,7 @@ describe API::Snippets, api: true do
end end
it 'creates a spam log' do it 'creates a spam log' do
expect { create_snippet(visibility_level: Snippet::PUBLIC) }. expect { create_snippet(visibility: 'public') }.
to change { SpamLog.count }.by(1) to change { SpamLog.count }.by(1)
end end
end end
...@@ -218,12 +218,12 @@ describe API::Snippets, api: true do ...@@ -218,12 +218,12 @@ describe API::Snippets, api: true do
let(:visibility_level) { Snippet::PRIVATE } let(:visibility_level) { Snippet::PRIVATE }
it 'rejects the snippet' do it 'rejects the snippet' do
expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }. expect { update_snippet(title: 'Foo', visibility: 'public') }.
not_to change { snippet.reload.title } not_to change { snippet.reload.title }
end end
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }. expect { update_snippet(title: 'Foo', visibility: 'public') }.
to change { SpamLog.count }.by(1) to change { SpamLog.count }.by(1)
end end
end end
......
require 'rails_helper'
describe API::V3::Snippets, api: true do
include ApiHelpers
let!(:user) { create(:user) }
describe 'GET /snippets/' do
it 'returns snippets available' do
public_snippet = create(:personal_snippet, :public, author: user)
private_snippet = create(:personal_snippet, :private, author: user)
internal_snippet = create(:personal_snippet, :internal, author: user)
get v3_api("/snippets/", user)
expect(response).to have_http_status(200)
expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly(
public_snippet.id,
internal_snippet.id,
private_snippet.id)
expect(json_response.last).to have_key('web_url')
expect(json_response.last).to have_key('raw_url')
end
it 'hides private snippets from regular user' do
create(:personal_snippet, :private)
get v3_api("/snippets/", user)
expect(response).to have_http_status(200)
expect(json_response.size).to eq(0)
end
end
describe 'GET /snippets/public' do
let!(:other_user) { create(:user) }
let!(:public_snippet) { create(:personal_snippet, :public, author: user) }
let!(:private_snippet) { create(:personal_snippet, :private, author: user) }
let!(:internal_snippet) { create(:personal_snippet, :internal, author: user) }
let!(:public_snippet_other) { create(:personal_snippet, :public, author: other_user) }
let!(:private_snippet_other) { create(:personal_snippet, :private, author: other_user) }
let!(:internal_snippet_other) { create(:personal_snippet, :internal, author: other_user) }
it 'returns all snippets with public visibility from all users' do
get v3_api("/snippets/public", user)
expect(response).to have_http_status(200)
expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly(
public_snippet.id,
public_snippet_other.id)
expect(json_response.map{ |snippet| snippet['web_url']} ).to include(
"http://localhost/snippets/#{public_snippet.id}",
"http://localhost/snippets/#{public_snippet_other.id}")
expect(json_response.map{ |snippet| snippet['raw_url']} ).to include(
"http://localhost/snippets/#{public_snippet.id}/raw",
"http://localhost/snippets/#{public_snippet_other.id}/raw")
end
end
describe 'GET /snippets/:id/raw' do
let(:snippet) { create(:personal_snippet, author: user) }
it 'returns raw text' do
get v3_api("/snippets/#{snippet.id}/raw", user)
expect(response).to have_http_status(200)
expect(response.content_type).to eq 'text/plain'
expect(response.body).to eq(snippet.content)
end
it 'returns 404 for invalid snippet id' do
delete v3_api("/snippets/1234", user)
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Snippet Not Found')
end
end
describe 'POST /snippets/' do
let(:params) do
{
title: 'Test Title',
file_name: 'test.rb',
content: 'puts "hello world"',
visibility_level: Snippet::PUBLIC
}
end
it 'creates a new snippet' do
expect do
post v3_api("/snippets/", user), params
end.to change { PersonalSnippet.count }.by(1)
expect(response).to have_http_status(201)
expect(json_response['title']).to eq(params[:title])
expect(json_response['file_name']).to eq(params[:file_name])
end
it 'returns 400 for missing parameters' do
params.delete(:title)
post v3_api("/snippets/", user), params
expect(response).to have_http_status(400)
end
context 'when the snippet is spam' do
def create_snippet(snippet_params = {})
post v3_api('/snippets', user), params.merge(snippet_params)
end
before do
allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
end
context 'when the snippet is private' do
it 'creates the snippet' do
expect { create_snippet(visibility_level: Snippet::PRIVATE) }.
to change { Snippet.count }.by(1)
end
end
context 'when the snippet is public' do
it 'rejects the shippet' do
expect { create_snippet(visibility_level: Snippet::PUBLIC) }.
not_to change { Snippet.count }
expect(response).to have_http_status(400)
end
it 'creates a spam log' do
expect { create_snippet(visibility_level: Snippet::PUBLIC) }.
to change { SpamLog.count }.by(1)
end
end
end
end
describe 'PUT /snippets/:id' do
let(:other_user) { create(:user) }
let(:public_snippet) { create(:personal_snippet, :public, author: user) }
it 'updates snippet' do
new_content = 'New content'
put v3_api("/snippets/#{public_snippet.id}", user), content: new_content
expect(response).to have_http_status(200)
public_snippet.reload
expect(public_snippet.content).to eq(new_content)
end
it 'returns 404 for invalid snippet id' do
put v3_api("/snippets/1234", user), title: 'foo'
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Snippet Not Found')
end
it "returns 404 for another user's snippet" do
put v3_api("/snippets/#{public_snippet.id}", other_user), title: 'fubar'
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Snippet Not Found')
end
it 'returns 400 for missing parameters' do
put v3_api("/snippets/1234", user)
expect(response).to have_http_status(400)
end
end
describe 'DELETE /snippets/:id' do
let!(:public_snippet) { create(:personal_snippet, :public, author: user) }
it 'deletes snippet' do
expect do
delete v3_api("/snippets/#{public_snippet.id}", user)
expect(response).to have_http_status(204)
end.to change { PersonalSnippet.count }.by(-1)
end
it 'returns 404 for invalid snippet id' do
delete v3_api("/snippets/1234", user)
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Snippet Not Found')
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