gitlab-org--gitlab-foss/lib/api/v3/projects.rb
James Lopez a0101ebf84 Update occurrences of MWBS to MWPS
Rename column in the database
 Rename fields related to import/export feature
 Rename API endpoints
 Rename documentation links
 Rename the rest of occurrences in the code
 Replace the images that contain the words "build succeeds" and docs referencing to them
 Make sure pipeline is green and nothing is missing.

updated doc images

renamed only_allow_merge_if_build_succeeds in projects and fixed references

more updates

fix some spec failures

fix rubocop offences

fix v3 api spec

fix MR  specs

fixed issues with partials

fix MR spec

fix alignment

add missing v3 to v4 doc

wip - refactor v3 endpoints

fix specs

fix a few typos

fix project specs

copy entities fully to V3

fix  entity error

more fixes

fix failing specs

fixed missing entities in V3 API

remove comment

updated code based on feedback

typo

fix spec
2017-03-01 12:02:02 +01:00

474 lines
18 KiB
Ruby

module API
module V3
class Projects < Grape::API
include PaginationParams
before { authenticate_non_get! }
after_validation do
set_only_allow_merge_if_pipeline_succeeds!
end
helpers do
params :optional_params do
optional :description, type: String, desc: 'The description of the project'
optional :issues_enabled, type: Boolean, desc: 'Flag indication if the issue tracker is enabled'
optional :merge_requests_enabled, type: Boolean, desc: 'Flag indication if merge requests are enabled'
optional :wiki_enabled, type: Boolean, desc: 'Flag indication if the wiki is enabled'
optional :builds_enabled, type: Boolean, desc: 'Flag indication if builds are enabled'
optional :snippets_enabled, type: Boolean, desc: 'Flag indication if snippets are enabled'
optional :shared_runners_enabled, type: Boolean, desc: 'Flag indication if shared runners are enabled for that project'
optional :container_registry_enabled, type: Boolean, desc: 'Flag indication if the container registry is enabled for that project'
optional :lfs_enabled, type: Boolean, desc: 'Flag indication if Git LFS is enabled for that project'
optional :public, type: Boolean, desc: 'Create a public project. The same as visibility_level = 20.'
optional :visibility_level, type: Integer, values: [
Gitlab::VisibilityLevel::PRIVATE,
Gitlab::VisibilityLevel::INTERNAL,
Gitlab::VisibilityLevel::PUBLIC
], desc: 'Create a public project. The same as visibility_level = 20.'
optional :public_builds, type: Boolean, desc: 'Perform public builds'
optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
optional :only_allow_merge_if_build_succeeds, type: Boolean, desc: 'Only allow to merge if builds succeed'
optional :only_allow_merge_if_pipeline_succeeds, type: Boolean, desc: 'Only allow to merge if builds succeed'
optional :only_allow_merge_if_all_discussions_are_resolved, type: Boolean, desc: 'Only allow to merge if all discussions are resolved'
end
def map_public_to_visibility_level(attrs)
publik = attrs.delete(:public)
if !publik.nil? && !attrs[:visibility_level].present?
# Since setting the public attribute to private could mean either
# private or internal, use the more conservative option, private.
attrs[:visibility_level] = (publik == true) ? Gitlab::VisibilityLevel::PUBLIC : Gitlab::VisibilityLevel::PRIVATE
end
attrs
end
def set_only_allow_merge_if_pipeline_succeeds!
if params.has_key?(:only_allow_merge_if_build_succeeds)
params[:only_allow_merge_if_pipeline_succeeds] = params.delete(:only_allow_merge_if_build_succeeds)
end
end
end
resource :projects do
helpers do
params :collection_params do
use :sort_params
use :filter_params
use :pagination
optional :simple, type: Boolean, default: false,
desc: 'Return only the ID, URL, name, and path of each project'
end
params :sort_params do
optional :order_by, type: String, values: %w[id name path created_at updated_at last_activity_at],
default: 'created_at', desc: 'Return projects ordered by field'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return projects sorted in ascending and descending order'
end
params :filter_params do
optional :archived, type: Boolean, default: false, desc: 'Limit by archived status'
optional :visibility, type: String, values: %w[public internal private],
desc: 'Limit by visibility'
optional :search, type: String, desc: 'Return list of authorized projects matching the search criteria'
end
params :statistics_params do
optional :statistics, type: Boolean, default: false, desc: 'Include project statistics'
end
params :create_params do
optional :namespace_id, type: Integer, desc: 'Namespace ID for the new project. Default to the user namespace.'
optional :import_url, type: String, desc: 'URL from which the project is imported'
end
def present_projects(projects, options = {})
options = options.reverse_merge(
with: ::API::V3::Entities::Project,
current_user: current_user,
simple: params[:simple],
)
projects = filter_projects(projects)
projects = projects.with_statistics if options[:statistics]
options[:with] = ::API::Entities::BasicProjectDetails if options[:simple]
present paginate(projects), options
end
end
desc 'Get a list of visible projects for authenticated user' do
success ::API::Entities::BasicProjectDetails
end
params do
use :collection_params
end
get '/visible' do
entity = current_user ? ::API::V3::Entities::ProjectWithAccess : ::API::Entities::BasicProjectDetails
present_projects ProjectsFinder.new.execute(current_user), with: entity
end
desc 'Get a projects list for authenticated user' do
success ::API::Entities::BasicProjectDetails
end
params do
use :collection_params
end
get do
authenticate!
present_projects current_user.authorized_projects,
with: ::API::V3::Entities::ProjectWithAccess
end
desc 'Get an owned projects list for authenticated user' do
success ::API::Entities::BasicProjectDetails
end
params do
use :collection_params
use :statistics_params
end
get '/owned' do
authenticate!
present_projects current_user.owned_projects,
with: ::API::V3::Entities::ProjectWithAccess,
statistics: params[:statistics]
end
desc 'Gets starred project for the authenticated user' do
success ::API::Entities::BasicProjectDetails
end
params do
use :collection_params
end
get '/starred' do
authenticate!
present_projects current_user.viewable_starred_projects
end
desc 'Get all projects for admin user' do
success ::API::Entities::BasicProjectDetails
end
params do
use :collection_params
use :statistics_params
end
get '/all' do
authenticated_as_admin!
present_projects Project.all, with: ::API::V3::Entities::ProjectWithAccess, statistics: params[:statistics]
end
desc 'Search for projects the current user has access to' do
success ::API::V3::Entities::Project
end
params do
requires :query, type: String, desc: 'The project name to be searched'
use :sort_params
use :pagination
end
get "/search/:query", requirements: { query: /[^\/]+/ } do
search_service = Search::GlobalService.new(current_user, search: params[:query]).execute
projects = search_service.objects('projects', params[:page])
projects = projects.reorder(params[:order_by] => params[:sort])
present paginate(projects), with: ::API::V3::Entities::Project
end
desc 'Create new project' do
success ::API::V3::Entities::Project
end
params do
optional :name, type: String, desc: 'The name of the project'
optional :path, type: String, desc: 'The path of the repository'
at_least_one_of :name, :path
use :optional_params
use :create_params
end
post do
attrs = map_public_to_visibility_level(declared_params(include_missing: false))
project = ::Projects::CreateService.new(current_user, attrs).execute
if project.saved?
present project, with: ::API::V3::Entities::Project,
user_can_admin_project: can?(current_user, :admin_project, project)
else
if project.errors[:limit_reached].present?
error!(project.errors[:limit_reached], 403)
end
render_validation_error!(project)
end
end
desc 'Create new project for a specified user. Only available to admin users.' do
success ::API::V3::Entities::Project
end
params do
requires :name, type: String, desc: 'The name of the project'
requires :user_id, type: Integer, desc: 'The ID of a user'
optional :default_branch, type: String, desc: 'The default branch of the project'
use :optional_params
use :create_params
end
post "user/:user_id" do
authenticated_as_admin!
user = User.find_by(id: params.delete(:user_id))
not_found!('User') unless user
attrs = map_public_to_visibility_level(declared_params(include_missing: false))
project = ::Projects::CreateService.new(user, attrs).execute
if project.saved?
present project, with: ::API::V3::Entities::Project,
user_can_admin_project: can?(current_user, :admin_project, project)
else
render_validation_error!(project)
end
end
end
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: { id: /[^\/]+/ } do
desc 'Get a single project' do
success ::API::V3::Entities::ProjectWithAccess
end
get ":id" do
entity = current_user ? ::API::V3::Entities::ProjectWithAccess : ::API::Entities::BasicProjectDetails
present user_project, with: entity, current_user: current_user,
user_can_admin_project: can?(current_user, :admin_project, user_project)
end
desc 'Get events for a single project' do
success ::API::V3::Entities::Event
end
params do
use :pagination
end
get ":id/events" do
present paginate(user_project.events.recent), with: ::API::V3::Entities::Event
end
desc 'Fork new project for the current user or provided namespace.' do
success ::API::V3::Entities::Project
end
params do
optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be forked into'
end
post 'fork/:id' do
fork_params = declared_params(include_missing: false)
namespace_id = fork_params[:namespace]
if namespace_id.present?
fork_params[:namespace] = if namespace_id =~ /^\d+$/
Namespace.find_by(id: namespace_id)
else
Namespace.find_by_path_or_name(namespace_id)
end
unless fork_params[:namespace] && can?(current_user, :create_projects, fork_params[:namespace])
not_found!('Target Namespace')
end
end
forked_project = ::Projects::ForkService.new(user_project, current_user, fork_params).execute
if forked_project.errors.any?
conflict!(forked_project.errors.messages)
else
present forked_project, with: ::API::V3::Entities::Project,
user_can_admin_project: can?(current_user, :admin_project, forked_project)
end
end
desc 'Update an existing project' do
success ::API::V3::Entities::Project
end
params do
optional :name, type: String, desc: 'The name of the project'
optional :default_branch, type: String, desc: 'The default branch of the project'
optional :path, type: String, desc: 'The path of the repository'
use :optional_params
at_least_one_of :name, :description, :issues_enabled, :merge_requests_enabled,
:wiki_enabled, :builds_enabled, :snippets_enabled,
:shared_runners_enabled, :container_registry_enabled,
:lfs_enabled, :public, :visibility_level, :public_builds,
:request_access_enabled, :only_allow_merge_if_build_succeeds,
:only_allow_merge_if_all_discussions_are_resolved, :path,
:default_branch
end
put ':id' do
authorize_admin_project
attrs = map_public_to_visibility_level(declared_params(include_missing: false))
authorize! :rename_project, user_project if attrs[:name].present?
authorize! :change_visibility_level, user_project if attrs[:visibility_level].present?
result = ::Projects::UpdateService.new(user_project, current_user, attrs).execute
if result[:status] == :success
present user_project, with: ::API::V3::Entities::Project,
user_can_admin_project: can?(current_user, :admin_project, user_project)
else
render_validation_error!(user_project)
end
end
desc 'Archive a project' do
success ::API::V3::Entities::Project
end
post ':id/archive' do
authorize!(:archive_project, user_project)
user_project.archive!
present user_project, with: ::API::V3::Entities::Project
end
desc 'Unarchive a project' do
success ::API::V3::Entities::Project
end
post ':id/unarchive' do
authorize!(:archive_project, user_project)
user_project.unarchive!
present user_project, with: ::API::V3::Entities::Project
end
desc 'Star a project' do
success ::API::V3::Entities::Project
end
post ':id/star' do
if current_user.starred?(user_project)
not_modified!
else
current_user.toggle_star(user_project)
user_project.reload
present user_project, with: ::API::V3::Entities::Project
end
end
desc 'Unstar a project' do
success ::API::V3::Entities::Project
end
delete ':id/star' do
if current_user.starred?(user_project)
current_user.toggle_star(user_project)
user_project.reload
present user_project, with: ::API::V3::Entities::Project
else
not_modified!
end
end
desc 'Remove a project'
delete ":id" do
authorize! :remove_project, user_project
status(200)
::Projects::DestroyService.new(user_project, current_user, {}).async_execute
end
desc 'Mark this project as forked from another'
params do
requires :forked_from_id, type: String, desc: 'The ID of the project it was forked from'
end
post ":id/fork/:forked_from_id" do
authenticated_as_admin!
forked_from_project = find_project!(params[:forked_from_id])
not_found!("Source Project") unless forked_from_project
if user_project.forked_from_project.nil?
user_project.create_forked_project_link(forked_to_project_id: user_project.id, forked_from_project_id: forked_from_project.id)
else
render_api_error!("Project already forked", 409)
end
end
desc 'Remove a forked_from relationship'
delete ":id/fork" do
authorize! :remove_fork_project, user_project
if user_project.forked?
status(200)
user_project.forked_project_link.destroy
else
not_modified!
end
end
desc 'Share the project with a group' do
success ::API::Entities::ProjectGroupLink
end
params do
requires :group_id, type: Integer, desc: 'The ID of a group'
requires :group_access, type: Integer, values: Gitlab::Access.values, desc: 'The group access level'
optional :expires_at, type: Date, desc: 'Share expiration date'
end
post ":id/share" do
authorize! :admin_project, user_project
group = Group.find_by_id(params[:group_id])
unless group && can?(current_user, :read_group, group)
not_found!('Group')
end
unless user_project.allowed_to_share_with_group?
return render_api_error!("The project sharing with group is disabled", 400)
end
link = user_project.project_group_links.new(declared_params(include_missing: false))
if link.save
present link, with: ::API::Entities::ProjectGroupLink
else
render_api_error!(link.errors.full_messages.first, 409)
end
end
params do
requires :group_id, type: Integer, desc: 'The ID of the group'
end
delete ":id/share/:group_id" do
authorize! :admin_project, user_project
link = user_project.project_group_links.find_by(group_id: params[:group_id])
not_found!('Group Link') unless link
link.destroy
no_content!
end
desc 'Upload a file'
params do
requires :file, type: File, desc: 'The file to be uploaded'
end
post ":id/uploads" do
::Projects::UploadService.new(user_project, params[:file]).execute
end
desc 'Get the users list of a project' do
success ::API::Entities::UserBasic
end
params do
optional :search, type: String, desc: 'Return list of users matching the search criteria'
use :pagination
end
get ':id/users' do
users = user_project.team.users
users = users.search(params[:search]) if params[:search].present?
present paginate(users), with: ::API::Entities::UserBasic
end
end
end
end
end