Commit e49b6364 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'feature_api_project_edit' into 'master'

API: Implement edit via API for projects

I've picked up https://github.com/gitlabhq/gitlabhq/pull/8055 fixed the few hound warnings and replaced all double quotes in the spec file where possible.

# From the original PR:

Implements edit via API for projects. Edit was part of missing features in feature request Full CRUD operations via API for projects.
http://feedback.gitlab.com/forums/176466-general/suggestions/3904506-full-crud-operations-via-api-for-projects

Feature is implemented using existing UpdateService for projects. Permission to change visibility level and name are checked in addition to check for permission to administer project.

Doesn't allow updating project namespace id, because there was existing API-method for transferring project to a group.

Documentation added to doc/api/projects.md. Uses API request PUT /projects/:id .

Tests included for:
1. Success for changing path
2. Success for changing name
3. Success for changing visibility level
4. Success for changing all other attributes
5. Success for changing name & path to existing name & path but in different namespace
6. Failure if not authenticated
7. Failure if path exists in project's namespace
8. Failure if name exists in project's namespace
9. Failure if not sufficient permission to change name
10. Failure if not sufficient permission to change visibility level
11. Failure if not sufficient permission to change other attributes

Allows updating following parameters:

* name
* path
* visibility_level
* public
* default_branch
* issues_enabled
* wiki_enabled
* snippets_enabled
* merge_requests_enabled
* description

See merge request !310
parents 4a10b750 47625ab7
...@@ -55,6 +55,7 @@ v 7.8.0 ...@@ -55,6 +55,7 @@ v 7.8.0
- -
- -
- -
- API: Add support for editing an existing project (Mika Mäenpää and Hannes Rosenögger)
- -
- -
- -
......
...@@ -287,6 +287,31 @@ Parameters: ...@@ -287,6 +287,31 @@ Parameters:
- `visibility_level` (optional) - `visibility_level` (optional)
- `import_url` (optional) - `import_url` (optional)
### Edit project
Updates an existing project
```
PUT /projects/:id
```
Parameters:
- `id` (required) - The ID of a project
- `name` (optional) - project name
- `path` (optional) - repository name for project
- `description` (optional) - short project description
- `default_branch` (optional)
- `issues_enabled` (optional)
- `merge_requests_enabled` (optional)
- `wiki_enabled` (optional)
- `snippets_enabled` (optional)
- `public` (optional) - if `true` same as setting visibility_level = 20
- `visibility_level` (optional)
On success, method returns 200 with the updated project. If parameters are
invalid, 400 is returned.
### Fork project ### Fork project
Forks a project into the user namespace of the authenticated user. Forks a project into the user namespace of the authenticated user.
......
...@@ -200,6 +200,49 @@ module API ...@@ -200,6 +200,49 @@ module API
end end
end end
# Update an existing project
#
# Parameters:
# id (required) - the id of a project
# name (optional) - name of a project
# path (optional) - path of a project
# description (optional) - short project description
# issues_enabled (optional)
# merge_requests_enabled (optional)
# wiki_enabled (optional)
# snippets_enabled (optional)
# public (optional) - if true same as setting visibility_level = 20
# visibility_level (optional) - visibility level of a project
# Example Request
# PUT /projects/:id
put ':id' do
attrs = attributes_for_keys [:name,
:path,
:description,
:default_branch,
:issues_enabled,
:merge_requests_enabled,
:wiki_enabled,
:snippets_enabled,
:public,
:visibility_level]
attrs = map_public_to_visibility_level(attrs)
authorize_admin_project
authorize! :rename_project, user_project if attrs[:name].present?
if attrs[:visibility_level].present?
authorize! :change_visibility_level, user_project
end
::Projects::UpdateService.new(user_project,
current_user, attrs).execute
if user_project.valid?
present user_project, with: Entities::Project
else
render_validation_error!(user_project)
end
end
# Remove project # Remove project
# #
# Parameters: # Parameters:
......
# -*- coding: utf-8 -*-
require 'spec_helper' require 'spec_helper'
describe API::API, api: true do describe API::API, api: true do
...@@ -12,43 +13,67 @@ describe API::API, api: true do ...@@ -12,43 +13,67 @@ describe API::API, api: true do
let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') }
let(:project_member) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) } let(:project_member) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) }
let(:project_member2) { create(:project_member, user: user3, project: project, access_level: ProjectMember::DEVELOPER) } let(:project_member2) { create(:project_member, user: user3, project: project, access_level: ProjectMember::DEVELOPER) }
let(:user4) { create(:user) }
let(:project3) do
create(:project,
name: 'second_project',
path: 'second_project',
creator_id: user.id,
namespace: user.namespace,
merge_requests_enabled: false,
issues_enabled: false, wiki_enabled: false,
snippets_enabled: false, visibility_level: 0)
end
let(:project_member3) do
create(:project_member,
user: user4,
project: project3,
access_level: ProjectMember::MASTER)
end
let(:project4) do
create(:project,
name: 'third_project',
path: 'third_project',
creator_id: user4.id,
namespace: user4.namespace)
end
describe "GET /projects" do describe 'GET /projects' do
before { project } before { project }
context "when unauthenticated" do context 'when unauthenticated' do
it "should return authentication error" do it 'should return authentication error' do
get api("/projects") get api('/projects')
response.status.should == 401 response.status.should == 401
end end
end end
context "when authenticated" do context 'when authenticated' do
it "should return an array of projects" do it 'should return an array of projects' do
get api("/projects", user) get api('/projects', user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.first['name'].should == project.name json_response.first['name'].should == project.name
json_response.first['owner']['username'].should == user.username json_response.first['owner']['username'].should == user.username
end end
context "and using search" do context 'and using search' do
it "should return searched project" do it 'should return searched project' do
get api("/projects", user), { search: project.name } get api('/projects', user), { search: project.name }
response.status.should eq(200) response.status.should eq(200)
json_response.should be_an Array json_response.should be_an Array
json_response.length.should eq(1) json_response.length.should eq(1)
end end
end end
context "and using sorting" do context 'and using sorting' do
before do before do
project2 project2
project3 project3
end end
it "should return the correct order when sorted by id" do it 'should return the correct order when sorted by id' do
get api("/projects", user), { order_by: 'id', sort: 'desc'} get api('/projects', user), { order_by: 'id', sort: 'desc'}
response.status.should eq(200) response.status.should eq(200)
json_response.should be_an Array json_response.should be_an Array
json_response.first['id'].should eq(project3.id) json_response.first['id'].should eq(project3.id)
...@@ -57,26 +82,26 @@ describe API::API, api: true do ...@@ -57,26 +82,26 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/all" do describe 'GET /projects/all' do
before { project } before { project }
context "when unauthenticated" do context 'when unauthenticated' do
it "should return authentication error" do it 'should return authentication error' do
get api("/projects/all") get api('/projects/all')
response.status.should == 401 response.status.should == 401
end end
end end
context "when authenticated as regular user" do context 'when authenticated as regular user' do
it "should return authentication error" do it 'should return authentication error' do
get api("/projects/all", user) get api('/projects/all', user)
response.status.should == 403 response.status.should == 403
end end
end end
context "when authenticated as admin" do context 'when authenticated as admin' do
it "should return an array of all projects" do it 'should return an array of all projects' do
get api("/projects/all", admin) get api('/projects/all', admin)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
project_name = project.name project_name = project.name
...@@ -92,59 +117,59 @@ describe API::API, api: true do ...@@ -92,59 +117,59 @@ describe API::API, api: true do
end end
end end
describe "POST /projects" do describe 'POST /projects' do
context "maximum number of projects reached" do context 'maximum number of projects reached' do
before do before do
(1..user2.projects_limit).each do |project| (1..user2.projects_limit).each do |project|
post api("/projects", user2), name: "foo#{project}" post api('/projects', user2), name: "foo#{project}"
end end
end end
it "should not create new project" do it 'should not create new project' do
expect { expect {
post api("/projects", user2), name: 'foo' post api('/projects', user2), name: 'foo'
}.to change {Project.count}.by(0) }.to change {Project.count}.by(0)
end end
end end
it "should create new project without path" do it 'should create new project without path' do
expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1) expect { post api('/projects', user), name: 'foo' }.to change {Project.count}.by(1)
end end
it "should not create new project without name" do it 'should not create new project without name' do
expect { post api("/projects", user) }.to_not change {Project.count} expect { post api('/projects', user) }.to_not change {Project.count}
end end
it "should return a 400 error if name not given" do it 'should return a 400 error if name not given' do
post api("/projects", user) post api('/projects', user)
response.status.should == 400 response.status.should == 400
end end
it "should create last project before reaching project limit" do it 'should create last project before reaching project limit' do
(1..user2.projects_limit-1).each { |p| post api("/projects", user2), name: "foo#{p}" } (1..user2.projects_limit-1).each { |p| post api('/projects', user2), name: "foo#{p}" }
post api("/projects", user2), name: "foo" post api('/projects', user2), name: 'foo'
response.status.should == 201 response.status.should == 201
end end
it "should respond with 201 on success" do it 'should respond with 201 on success' do
post api("/projects", user), name: 'foo' post api('/projects', user), name: 'foo'
response.status.should == 201 response.status.should == 201
end end
it "should respond with 400 if name is not given" do it 'should respond with 400 if name is not given' do
post api("/projects", user) post api('/projects', user)
response.status.should == 400 response.status.should == 400
end end
it "should return a 403 error if project limit reached" do it 'should return a 403 error if project limit reached' do
(1..user.projects_limit).each do |p| (1..user.projects_limit).each do |p|
post api("/projects", user), name: "foo#{p}" post api('/projects', user), name: "foo#{p}"
end end
post api("/projects", user), name: 'bar' post api('/projects', user), name: 'bar'
response.status.should == 403 response.status.should == 403
end end
it "should assign attributes to project" do it 'should assign attributes to project' do
project = attributes_for(:project, { project = attributes_for(:project, {
path: 'camelCasePath', path: 'camelCasePath',
description: Faker::Lorem.sentence, description: Faker::Lorem.sentence,
...@@ -153,69 +178,69 @@ describe API::API, api: true do ...@@ -153,69 +178,69 @@ describe API::API, api: true do
wiki_enabled: false wiki_enabled: false
}) })
post api("/projects", user), project post api('/projects', user), project
project.each_pair do |k,v| project.each_pair do |k,v|
json_response[k.to_s].should == v json_response[k.to_s].should == v
end end
end end
it "should set a project as public" do it 'should set a project as public' do
project = attributes_for(:project, :public) project = attributes_for(:project, :public)
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_true json_response['public'].should be_true
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
end end
it "should set a project as public using :public" do it 'should set a project as public using :public' do
project = attributes_for(:project, { public: true }) project = attributes_for(:project, { public: true })
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_true json_response['public'].should be_true
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
end end
it "should set a project as internal" do it 'should set a project as internal' do
project = attributes_for(:project, :internal) project = attributes_for(:project, :internal)
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as internal overriding :public" do it 'should set a project as internal overriding :public' do
project = attributes_for(:project, :internal, { public: true }) project = attributes_for(:project, :internal, { public: true })
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as private" do it 'should set a project as private' do
project = attributes_for(:project, :private) project = attributes_for(:project, :private)
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
end end
it "should set a project as private using :public" do it 'should set a project as private using :public' do
project = attributes_for(:project, { public: false }) project = attributes_for(:project, { public: false })
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
end end
end end
describe "POST /projects/user/:id" do describe 'POST /projects/user/:id' do
before { project } before { project }
before { admin } before { admin }
it "should create new project without path" do it 'should create new project without path' do
expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1) expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
end end
it "should not create new project without name" do it 'should not create new project without name' do
expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count} expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count}
end end
it "should respond with 201 on success" do it 'should respond with 201 on success' do
post api("/projects/user/#{user.id}", admin), name: 'foo' post api("/projects/user/#{user.id}", admin), name: 'foo'
response.status.should == 201 response.status.should == 201
end end
...@@ -235,7 +260,7 @@ describe API::API, api: true do ...@@ -235,7 +260,7 @@ describe API::API, api: true do
] ]
end end
it "should assign attributes to project" do it 'should assign attributes to project' do
project = attributes_for(:project, { project = attributes_for(:project, {
description: Faker::Lorem.sentence, description: Faker::Lorem.sentence,
issues_enabled: false, issues_enabled: false,
...@@ -251,42 +276,42 @@ describe API::API, api: true do ...@@ -251,42 +276,42 @@ describe API::API, api: true do
end end
end end
it "should set a project as public" do it 'should set a project as public' do
project = attributes_for(:project, :public) project = attributes_for(:project, :public)
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_true json_response['public'].should be_true
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
end end
it "should set a project as public using :public" do it 'should set a project as public using :public' do
project = attributes_for(:project, { public: true }) project = attributes_for(:project, { public: true })
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_true json_response['public'].should be_true
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
end end
it "should set a project as internal" do it 'should set a project as internal' do
project = attributes_for(:project, :internal) project = attributes_for(:project, :internal)
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as internal overriding :public" do it 'should set a project as internal overriding :public' do
project = attributes_for(:project, :internal, { public: true }) project = attributes_for(:project, :internal, { public: true })
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as private" do it 'should set a project as private' do
project = attributes_for(:project, :private) project = attributes_for(:project, :private)
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
end end
it "should set a project as private using :public" do it 'should set a project as private using :public' do
project = attributes_for(:project, { public: false }) project = attributes_for(:project, { public: false })
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
...@@ -294,30 +319,30 @@ describe API::API, api: true do ...@@ -294,30 +319,30 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/:id" do describe 'GET /projects/:id' do
before { project } before { project }
before { project_member } before { project_member }
it "should return a project by id" do it 'should return a project by id' do
get api("/projects/#{project.id}", user) get api("/projects/#{project.id}", user)
response.status.should == 200 response.status.should == 200
json_response['name'].should == project.name json_response['name'].should == project.name
json_response['owner']['username'].should == user.username json_response['owner']['username'].should == user.username
end end
it "should return a project by path name" do it 'should return a project by path name' do
get api("/projects/#{project.id}", user) get api("/projects/#{project.id}", user)
response.status.should == 200 response.status.should == 200
json_response['name'].should == project.name json_response['name'].should == project.name
end end
it "should return a 404 error if not found" do it 'should return a 404 error if not found' do
get api("/projects/42", user) get api('/projects/42', user)
response.status.should == 404 response.status.should == 404
json_response['message'].should == '404 Project Not Found' json_response['message'].should == '404 Project Not Found'
end end
it "should return a 404 error if user is not a member" do it 'should return a 404 error if user is not a member' do
other_user = create(:user) other_user = create(:user)
get api("/projects/#{project.id}", other_user) get api("/projects/#{project.id}", other_user)
response.status.should == 404 response.status.should == 404
...@@ -331,8 +356,8 @@ describe API::API, api: true do ...@@ -331,8 +356,8 @@ describe API::API, api: true do
end end
it { response.status.should == 200 } it { response.status.should == 200 }
it { json_response['permissions']["project_access"]["access_level"].should == Gitlab::Access::MASTER } it { json_response['permissions']['project_access']['access_level'].should == Gitlab::Access::MASTER }
it { json_response['permissions']["group_access"].should be_nil } it { json_response['permissions']['group_access'].should be_nil }
end end
context 'group project' do context 'group project' do
...@@ -343,16 +368,16 @@ describe API::API, api: true do ...@@ -343,16 +368,16 @@ describe API::API, api: true do
end end
it { response.status.should == 200 } it { response.status.should == 200 }
it { json_response['permissions']["project_access"].should be_nil } it { json_response['permissions']['project_access'].should be_nil }
it { json_response['permissions']["group_access"]["access_level"].should == Gitlab::Access::OWNER } it { json_response['permissions']['group_access']['access_level'].should == Gitlab::Access::OWNER }
end end
end end
end end
describe "GET /projects/:id/events" do describe 'GET /projects/:id/events' do
before { project_member } before { project_member }
it "should return a project events" do it 'should return a project events' do
get api("/projects/#{project.id}/events", user) get api("/projects/#{project.id}/events", user)
response.status.should == 200 response.status.should == 200
json_event = json_response.first json_event = json_response.first
...@@ -362,23 +387,23 @@ describe API::API, api: true do ...@@ -362,23 +387,23 @@ describe API::API, api: true do
json_event['author_username'].should == user.username json_event['author_username'].should == user.username
end end
it "should return a 404 error if not found" do it 'should return a 404 error if not found' do
get api("/projects/42/events", user) get api('/projects/42/events', user)
response.status.should == 404 response.status.should == 404
json_response['message'].should == '404 Project Not Found' json_response['message'].should == '404 Project Not Found'
end end
it "should return a 404 error if user is not a member" do it 'should return a 404 error if user is not a member' do
other_user = create(:user) other_user = create(:user)
get api("/projects/#{project.id}/events", other_user) get api("/projects/#{project.id}/events", other_user)
response.status.should == 404 response.status.should == 404
end end
end end
describe "GET /projects/:id/snippets" do describe 'GET /projects/:id/snippets' do
before { snippet } before { snippet }
it "should return an array of project snippets" do it 'should return an array of project snippets' do
get api("/projects/#{project.id}/snippets", user) get api("/projects/#{project.id}/snippets", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
...@@ -386,48 +411,48 @@ describe API::API, api: true do ...@@ -386,48 +411,48 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/:id/snippets/:snippet_id" do describe 'GET /projects/:id/snippets/:snippet_id' do
it "should return a project snippet" do it 'should return a project snippet' do
get api("/projects/#{project.id}/snippets/#{snippet.id}", user) get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
response.status.should == 200 response.status.should == 200
json_response['title'].should == snippet.title json_response['title'].should == snippet.title
end end
it "should return a 404 error if snippet id not found" do it 'should return a 404 error if snippet id not found' do
get api("/projects/#{project.id}/snippets/1234", user) get api("/projects/#{project.id}/snippets/1234", user)
response.status.should == 404 response.status.should == 404
end end
end end
describe "POST /projects/:id/snippets" do describe 'POST /projects/:id/snippets' do
it "should create a new project snippet" do it 'should create a new project snippet' do
post api("/projects/#{project.id}/snippets", user), post api("/projects/#{project.id}/snippets", user),
title: 'api test', file_name: 'sample.rb', code: 'test' title: 'api test', file_name: 'sample.rb', code: 'test'
response.status.should == 201 response.status.should == 201
json_response['title'].should == 'api test' json_response['title'].should == 'api test'
end end
it "should return a 400 error if title is not given" do it 'should return a 400 error if title is not given' do
post api("/projects/#{project.id}/snippets", user), post api("/projects/#{project.id}/snippets", user),
file_name: 'sample.rb', code: 'test' file_name: 'sample.rb', code: 'test'
response.status.should == 400 response.status.should == 400
end end
it "should return a 400 error if file_name not given" do it 'should return a 400 error if file_name not given' do
post api("/projects/#{project.id}/snippets", user), post api("/projects/#{project.id}/snippets", user),
title: 'api test', code: 'test' title: 'api test', code: 'test'
response.status.should == 400 response.status.should == 400
end end
it "should return a 400 error if code not given" do it 'should return a 400 error if code not given' do
post api("/projects/#{project.id}/snippets", user), post api("/projects/#{project.id}/snippets", user),
title: 'api test', file_name: 'sample.rb' title: 'api test', file_name: 'sample.rb'
response.status.should == 400 response.status.should == 400
end end
end end
describe "PUT /projects/:id/snippets/:shippet_id" do describe 'PUT /projects/:id/snippets/:shippet_id' do
it "should update an existing project snippet" do it 'should update an existing project snippet' do
put api("/projects/#{project.id}/snippets/#{snippet.id}", user), put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
code: 'updated code' code: 'updated code'
response.status.should == 200 response.status.should == 200
...@@ -435,7 +460,7 @@ describe API::API, api: true do ...@@ -435,7 +460,7 @@ describe API::API, api: true do
snippet.reload.content.should == 'updated code' snippet.reload.content.should == 'updated code'
end end
it "should update an existing project snippet with new title" do it 'should update an existing project snippet with new title' do
put api("/projects/#{project.id}/snippets/#{snippet.id}", user), put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
title: 'other api test' title: 'other api test'
response.status.should == 200 response.status.should == 200
...@@ -443,10 +468,10 @@ describe API::API, api: true do ...@@ -443,10 +468,10 @@ describe API::API, api: true do
end end
end end
describe "DELETE /projects/:id/snippets/:snippet_id" do describe 'DELETE /projects/:id/snippets/:snippet_id' do
before { snippet } before { snippet }
it "should delete existing project snippet" do it 'should delete existing project snippet' do
expect { expect {
delete api("/projects/#{project.id}/snippets/#{snippet.id}", user) delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
}.to change { Snippet.count }.by(-1) }.to change { Snippet.count }.by(-1)
...@@ -459,13 +484,13 @@ describe API::API, api: true do ...@@ -459,13 +484,13 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/:id/snippets/:snippet_id/raw" do describe 'GET /projects/:id/snippets/:snippet_id/raw' do
it "should get a raw project snippet" do it 'should get a raw project snippet' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user) get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
response.status.should == 200 response.status.should == 200
end end
it "should return a 404 error if raw project snippet not found" do it 'should return a 404 error if raw project snippet not found' do
get api("/projects/#{project.id}/snippets/5555/raw", user) get api("/projects/#{project.id}/snippets/5555/raw", user)
response.status.should == 404 response.status.should == 404
end end
...@@ -475,10 +500,10 @@ describe API::API, api: true do ...@@ -475,10 +500,10 @@ describe API::API, api: true do
let(:deploy_keys_project) { create(:deploy_keys_project, project: project) } let(:deploy_keys_project) { create(:deploy_keys_project, project: project) }
let(:deploy_key) { deploy_keys_project.deploy_key } let(:deploy_key) { deploy_keys_project.deploy_key }
describe "GET /projects/:id/keys" do describe 'GET /projects/:id/keys' do
before { deploy_key } before { deploy_key }
it "should return array of ssh keys" do it 'should return array of ssh keys' do
get api("/projects/#{project.id}/keys", user) get api("/projects/#{project.id}/keys", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
...@@ -486,22 +511,22 @@ describe API::API, api: true do ...@@ -486,22 +511,22 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/:id/keys/:key_id" do describe 'GET /projects/:id/keys/:key_id' do
it "should return a single key" do it 'should return a single key' do
get api("/projects/#{project.id}/keys/#{deploy_key.id}", user) get api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
response.status.should == 200 response.status.should == 200
json_response['title'].should == deploy_key.title json_response['title'].should == deploy_key.title
end end
it "should return 404 Not Found with invalid ID" do it 'should return 404 Not Found with invalid ID' do
get api("/projects/#{project.id}/keys/404", user) get api("/projects/#{project.id}/keys/404", user)
response.status.should == 404 response.status.should == 404
end end
end end
describe "POST /projects/:id/keys" do describe 'POST /projects/:id/keys' do
it "should not create an invalid ssh key" do it 'should not create an invalid ssh key' do
post api("/projects/#{project.id}/keys", user), { title: "invalid key" } post api("/projects/#{project.id}/keys", user), { title: 'invalid key' }
response.status.should == 400 response.status.should == 400
json_response['message']['key'].should == [ json_response['message']['key'].should == [
'can\'t be blank', 'can\'t be blank',
...@@ -519,7 +544,7 @@ describe API::API, api: true do ...@@ -519,7 +544,7 @@ describe API::API, api: true do
] ]
end end
it "should create new ssh key" do it 'should create new ssh key' do
key_attrs = attributes_for :key key_attrs = attributes_for :key
expect { expect {
post api("/projects/#{project.id}/keys", user), key_attrs post api("/projects/#{project.id}/keys", user), key_attrs
...@@ -527,16 +552,16 @@ describe API::API, api: true do ...@@ -527,16 +552,16 @@ describe API::API, api: true do
end end
end end
describe "DELETE /projects/:id/keys/:key_id" do describe 'DELETE /projects/:id/keys/:key_id' do
before { deploy_key } before { deploy_key }
it "should delete existing key" do it 'should delete existing key' do
expect { expect {
delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user) delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
}.to change{ project.deploy_keys.count }.by(-1) }.to change{ project.deploy_keys.count }.by(-1)
end end
it "should return 404 Not Found with invalid ID" do it 'should return 404 Not Found with invalid ID' do
delete api("/projects/#{project.id}/keys/404", user) delete api("/projects/#{project.id}/keys/404", user)
response.status.should == 404 response.status.should == 404
end end
...@@ -547,7 +572,7 @@ describe API::API, api: true do ...@@ -547,7 +572,7 @@ describe API::API, api: true do
let(:project_fork_target) { create(:project) } let(:project_fork_target) { create(:project) }
let(:project_fork_source) { create(:project, :public) } let(:project_fork_source) { create(:project, :public) }
describe "POST /projects/:id/fork/:forked_from_id" do describe 'POST /projects/:id/fork/:forked_from_id' do
let(:new_project_fork_source) { create(:project, :public) } let(:new_project_fork_source) { create(:project, :public) }
it "shouldn't available for non admin users" do it "shouldn't available for non admin users" do
...@@ -555,7 +580,7 @@ describe API::API, api: true do ...@@ -555,7 +580,7 @@ describe API::API, api: true do
response.status.should == 403 response.status.should == 403
end end
it "should allow project to be forked from an existing project" do it 'should allow project to be forked from an existing project' do
project_fork_target.forked?.should_not be_true project_fork_target.forked?.should_not be_true
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
response.status.should == 201 response.status.should == 201
...@@ -565,12 +590,12 @@ describe API::API, api: true do ...@@ -565,12 +590,12 @@ describe API::API, api: true do
project_fork_target.forked?.should be_true project_fork_target.forked?.should be_true
end end
it "should fail if forked_from project which does not exist" do it 'should fail if forked_from project which does not exist' do
post api("/projects/#{project_fork_target.id}/fork/9999", admin) post api("/projects/#{project_fork_target.id}/fork/9999", admin)
response.status.should == 404 response.status.should == 404
end end
it "should fail with 409 if already forked" do it 'should fail with 409 if already forked' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
project_fork_target.reload project_fork_target.reload
project_fork_target.forked_from_project.id.should == project_fork_source.id project_fork_target.forked_from_project.id.should == project_fork_source.id
...@@ -582,14 +607,14 @@ describe API::API, api: true do ...@@ -582,14 +607,14 @@ describe API::API, api: true do
end end
end end
describe "DELETE /projects/:id/fork" do describe 'DELETE /projects/:id/fork' do
it "shouldn't available for non admin users" do it "shouldn't available for non admin users" do
delete api("/projects/#{project_fork_target.id}/fork", user) delete api("/projects/#{project_fork_target.id}/fork", user)
response.status.should == 403 response.status.should == 403
end end
it "should make forked project unforked" do it 'should make forked project unforked' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
project_fork_target.reload project_fork_target.reload
project_fork_target.forked_from_project.should_not be_nil project_fork_target.forked_from_project.should_not be_nil
...@@ -601,7 +626,7 @@ describe API::API, api: true do ...@@ -601,7 +626,7 @@ describe API::API, api: true do
project_fork_target.forked?.should_not be_true project_fork_target.forked?.should_not be_true
end end
it "should be idempotent if not forked" do it 'should be idempotent if not forked' do
project_fork_target.forked_from_project.should be_nil project_fork_target.forked_from_project.should be_nil
delete api("/projects/#{project_fork_target.id}/fork", admin) delete api("/projects/#{project_fork_target.id}/fork", admin)
response.status.should == 200 response.status.should == 200
...@@ -610,7 +635,7 @@ describe API::API, api: true do ...@@ -610,7 +635,7 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/search/:query" do describe 'GET /projects/search/:query' do
let!(:query) { 'query'} let!(:query) { 'query'}
let!(:search) { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) } let!(:search) { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) }
let!(:pre) { create(:empty_project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) } let!(:pre) { create(:empty_project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) }
...@@ -622,15 +647,15 @@ describe API::API, api: true do ...@@ -622,15 +647,15 @@ describe API::API, api: true do
let!(:public) { create(:empty_project, :public, name: "public #{query}") } let!(:public) { create(:empty_project, :public, name: "public #{query}") }
let!(:unfound_public) { create(:empty_project, :public, name: 'unfound public') } let!(:unfound_public) { create(:empty_project, :public, name: 'unfound public') }
context "when unauthenticated" do context 'when unauthenticated' do
it "should return authentication error" do it 'should return authentication error' do
get api("/projects/search/#{query}") get api("/projects/search/#{query}")
response.status.should == 401 response.status.should == 401
end end
end end
context "when authenticated" do context 'when authenticated' do
it "should return an array of projects" do it 'should return an array of projects' do
get api("/projects/search/#{query}",user) get api("/projects/search/#{query}",user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
...@@ -639,8 +664,8 @@ describe API::API, api: true do ...@@ -639,8 +664,8 @@ describe API::API, api: true do
end end
end end
context "when authenticated as a different user" do context 'when authenticated as a different user' do
it "should return matching public projects" do it 'should return matching public projects' do
get api("/projects/search/#{query}", user2) get api("/projects/search/#{query}", user2)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
...@@ -650,9 +675,121 @@ describe API::API, api: true do ...@@ -650,9 +675,121 @@ describe API::API, api: true do
end end
end end
describe "DELETE /projects/:id" do describe 'PUT /projects/:id̈́' do
context "when authenticated as user" do before { project }
it "should remove project" do before { user }
before { user3 }
before { user4 }
before { project3 }
before { project4 }
before { project_member3 }
before { project_member2 }
context 'when unauthenticated' do
it 'should return authentication error' do
project_param = { name: 'bar' }
put api("/projects/#{project.id}"), project_param
response.status.should == 401
end
end
context 'when authenticated as project owner' do
it 'should update name' do
project_param = { name: 'bar' }
put api("/projects/#{project.id}", user), project_param
response.status.should == 200
project_param.each_pair do |k, v|
json_response[k.to_s].should == v
end
end
it 'should update visibility_level' do
project_param = { visibility_level: 20 }
put api("/projects/#{project3.id}", user), project_param
response.status.should == 200
project_param.each_pair do |k, v|
json_response[k.to_s].should == v
end
end
it 'should not update name to existing name' do
project_param = { name: project3.name }
put api("/projects/#{project.id}", user), project_param
response.status.should == 400
json_response['message']['name'].should == ['has already been taken']
end
it 'should update path & name to existing path & name in different namespace' do
project_param = { path: project4.path, name: project4.name }
put api("/projects/#{project3.id}", user), project_param
response.status.should == 200
project_param.each_pair do |k, v|
json_response[k.to_s].should == v
end
end
end
context 'when authenticated as project master' do
it 'should update path' do
project_param = { path: 'bar' }
put api("/projects/#{project3.id}", user4), project_param
response.status.should == 200
project_param.each_pair do |k, v|
json_response[k.to_s].should == v
end
end
it 'should update other attributes' do
project_param = { issues_enabled: true,
wiki_enabled: true,
snippets_enabled: true,
merge_requests_enabled: true,
description: 'new description' }
put api("/projects/#{project3.id}", user4), project_param
response.status.should == 200
project_param.each_pair do |k, v|
json_response[k.to_s].should == v
end
end
it 'should not update path to existing path' do
project_param = { path: project.path }
put api("/projects/#{project3.id}", user4), project_param
response.status.should == 400
json_response['message']['path'].should == ['has already been taken']
end
it 'should not update name' do
project_param = { name: 'bar' }
put api("/projects/#{project3.id}", user4), project_param
response.status.should == 403
end
it 'should not update visibility_level' do
project_param = { visibility_level: 20 }
put api("/projects/#{project3.id}", user4), project_param
response.status.should == 403
end
end
context 'when authenticated as project developer' do
it 'should not update other attributes' do
project_param = { path: 'bar',
issues_enabled: true,
wiki_enabled: true,
snippets_enabled: true,
merge_requests_enabled: true,
description: 'new description' }
put api("/projects/#{project.id}", user3), project_param
response.status.should == 403
end
end
end
describe 'DELETE /projects/:id' do
context 'when authenticated as user' do
it 'should remove project' do
expect(GitlabShellWorker).to( expect(GitlabShellWorker).to(
receive(:perform_async).with(:remove_repository, receive(:perform_async).with(:remove_repository,
/#{project.path_with_namespace}/) /#{project.path_with_namespace}/)
...@@ -662,32 +799,32 @@ describe API::API, api: true do ...@@ -662,32 +799,32 @@ describe API::API, api: true do
response.status.should == 200 response.status.should == 200
end end
it "should not remove a project if not an owner" do it 'should not remove a project if not an owner' do
user3 = create(:user) user3 = create(:user)
project.team << [user3, :developer] project.team << [user3, :developer]
delete api("/projects/#{project.id}", user3) delete api("/projects/#{project.id}", user3)
response.status.should == 403 response.status.should == 403
end end
it "should not remove a non existing project" do it 'should not remove a non existing project' do
delete api("/projects/1328", user) delete api('/projects/1328', user)
response.status.should == 404 response.status.should == 404
end end
it "should not remove a project not attached to user" do it 'should not remove a project not attached to user' do
delete api("/projects/#{project.id}", user2) delete api("/projects/#{project.id}", user2)
response.status.should == 404 response.status.should == 404
end end
end end
context "when authenticated as admin" do context 'when authenticated as admin' do
it "should remove any existing project" do it 'should remove any existing project' do
delete api("/projects/#{project.id}", admin) delete api("/projects/#{project.id}", admin)
response.status.should == 200 response.status.should == 200
end end
it "should not remove a non existing project" do it 'should not remove a non existing project' do
delete api("/projects/1328", admin) delete api('/projects/1328', admin)
response.status.should == 404 response.status.should == 404
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