BigW Consortium Gitlab

projects.rb 15 KB
Newer Older
1
module API
2 3 4 5
  # Projects API
  class Projects < Grape::API
    before { authenticate! }

6
    resource :projects, requirements: { id: /[^\/]+/ } do
7
      helpers do
8 9
        def map_public_to_visibility_level(attrs)
          publik = attrs.delete(:public)
10 11 12 13 14 15
          if publik.present? && !attrs[:visibility_level].present?
            publik = parse_boolean(publik)
            # 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
16 17
          attrs
        end
18 19
      end

20 21 22 23 24
      # Get a projects list for authenticated user
      #
      # Example Request:
      #   GET /projects
      get do
25
        @projects = current_user.authorized_projects
26
        @projects = filter_projects(@projects)
27
        @projects = paginate @projects
28
        present @projects, with: Entities::ProjectWithAccess, user: current_user
29 30
      end

31 32 33 34 35
      # Get an owned projects list for authenticated user
      #
      # Example Request:
      #   GET /projects/owned
      get '/owned' do
36
        @projects = current_user.owned_projects
37
        @projects = filter_projects(@projects)
38
        @projects = paginate @projects
39
        present @projects, with: Entities::ProjectWithAccess, user: current_user
40 41
      end

42 43 44 45 46
      # Gets starred project for the authenticated user
      #
      # Example Request:
      #   GET /projects/starred
      get '/starred' do
47
        @projects = current_user.viewable_starred_projects
48 49 50 51 52
        @projects = filter_projects(@projects)
        @projects = paginate @projects
        present @projects, with: Entities::Project
      end

53 54 55 56 57 58
      # Get all projects for admin user
      #
      # Example Request:
      #   GET /projects/all
      get '/all' do
        authenticated_as_admin!
59 60
        @projects = Project.all
        @projects = filter_projects(@projects)
61
        @projects = paginate @projects
62
        present @projects, with: Entities::ProjectWithAccess, user: current_user
63 64
      end

65 66 67
      # Get a single project
      #
      # Parameters:
68
      #   id (required) - The ID of a project
69 70 71
      # Example Request:
      #   GET /projects/:id
      get ":id" do
72 73
        present user_project, with: Entities::ProjectWithAccess, user: current_user,
                              user_can_admin_project: can?(current_user, :admin_project, user_project)
74 75
      end

76
      # Get events for a single project
77 78 79 80
      #
      # Parameters:
      #   id (required) - The ID of a project
      # Example Request:
81
      #   GET /projects/:id/events
82
      get ":id/events" do
83
        events = paginate user_project.events.recent
84 85 86
        present events, with: Entities::Event
      end

87 88 89 90
      # Create new project
      #
      # Parameters:
      #   name (required) - name for new project
91
      #   description (optional) - short project description
92 93
      #   issues_enabled (optional)
      #   merge_requests_enabled (optional)
94
      #   builds_enabled (optional)
95
      #   wiki_enabled (optional)
96
      #   snippets_enabled (optional)
97
      #   shared_runners_enabled (optional)
98
      #   namespace_id (optional) - defaults to user namespace
99 100
      #   public (optional) - if true same as setting visibility_level = 20
      #   visibility_level (optional) - 0 by default
101
      #   import_url (optional)
102
      #   public_builds (optional)
103 104 105
      # Example Request
      #   POST /projects
      post do
106
        required_attributes! [:name]
107
        attrs = attributes_for_keys [:name,
108 109 110 111
                                     :path,
                                     :description,
                                     :issues_enabled,
                                     :merge_requests_enabled,
112
                                     :builds_enabled,
113 114
                                     :wiki_enabled,
                                     :snippets_enabled,
115
                                     :shared_runners_enabled,
116
                                     :namespace_id,
117
                                     :public,
118
                                     :visibility_level,
119
                                     :import_url,
120
                                     :public_builds]
121
        attrs = map_public_to_visibility_level(attrs)
122
        @project = ::Projects::CreateService.new(current_user, attrs).execute
123
        if @project.saved?
124 125
          present @project, with: Entities::Project,
                            user_can_admin_project: can?(current_user, :admin_project, @project)
126
        else
127 128 129
          if @project.errors[:limit_reached].present?
            error!(@project.errors[:limit_reached], 403)
          end
130
          render_validation_error!(@project)
131 132 133
        end
      end

Angus MacArthur committed
134 135 136 137 138 139 140
      # Create new project for a specified user.  Only available to admin users.
      #
      # Parameters:
      #   user_id (required) - The ID of a user
      #   name (required) - name for new project
      #   description (optional) - short project description
      #   default_branch (optional) - 'master' by default
141 142
      #   issues_enabled (optional)
      #   merge_requests_enabled (optional)
143
      #   builds_enabled (optional)
144 145
      #   wiki_enabled (optional)
      #   snippets_enabled (optional)
146
      #   shared_runners_enabled (optional)
147 148
      #   public (optional) - if true same as setting visibility_level = 20
      #   visibility_level (optional)
149
      #   import_url (optional)
150
      #   public_builds (optional)
Angus MacArthur committed
151 152 153 154 155 156
      # Example Request
      #   POST /projects/user/:user_id
      post "user/:user_id" do
        authenticated_as_admin!
        user = User.find(params[:user_id])
        attrs = attributes_for_keys [:name,
157 158 159 160
                                     :description,
                                     :default_branch,
                                     :issues_enabled,
                                     :merge_requests_enabled,
161
                                     :builds_enabled,
162 163
                                     :wiki_enabled,
                                     :snippets_enabled,
164
                                     :shared_runners_enabled,
165
                                     :public,
166
                                     :visibility_level,
167
                                     :import_url,
168
                                     :public_builds]
169
        attrs = map_public_to_visibility_level(attrs)
170
        @project = ::Projects::CreateService.new(user, attrs).execute
Angus MacArthur committed
171
        if @project.saved?
172 173
          present @project, with: Entities::Project,
                            user_can_admin_project: can?(current_user, :admin_project, @project)
Angus MacArthur committed
174
        else
175
          render_validation_error!(@project)
Angus MacArthur committed
176 177 178
        end
      end

179 180 181 182 183 184 185 186 187 188 189 190 191
      # Fork new project for the current user.
      #
      # Parameters:
      #   id (required) - The ID of a project
      # Example Request
      #   POST /projects/fork/:id
      post 'fork/:id' do
        @forked_project =
          ::Projects::ForkService.new(user_project,
                                      current_user).execute
        if @forked_project.errors.any?
          conflict!(@forked_project.errors.messages)
        else
192 193
          present @forked_project, with: Entities::Project,
                                   user_can_admin_project: can?(current_user, :admin_project, @forked_project)
194
        end
195 196
      end

197 198 199 200 201 202 203 204 205
      # 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)
206
      #   builds_enabled (optional)
207 208
      #   wiki_enabled (optional)
      #   snippets_enabled (optional)
209
      #   shared_runners_enabled (optional)
210 211
      #   public (optional) - if true same as setting visibility_level = 20
      #   visibility_level (optional) - visibility level of a project
212
      #   public_builds (optional)
213 214 215 216 217 218 219 220 221
      # Example Request
      #   PUT /projects/:id
      put ':id' do
        attrs = attributes_for_keys [:name,
                                     :path,
                                     :description,
                                     :default_branch,
                                     :issues_enabled,
                                     :merge_requests_enabled,
222
                                     :builds_enabled,
223 224
                                     :wiki_enabled,
                                     :snippets_enabled,
225
                                     :shared_runners_enabled,
226
                                     :public,
227
                                     :visibility_level,
228
                                     :public_builds]
229 230 231 232 233 234 235 236 237 238
        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

239
        if user_project.errors.any?
240
          render_validation_error!(user_project)
241
        else
242 243
          present user_project, with: Entities::Project,
                                user_can_admin_project: can?(current_user, :admin_project, user_project)
244 245 246
        end
      end

247 248 249 250 251 252
      # Archive project
      #
      # Parameters:
      #   id (required) - The ID of a project
      # Example Request:
      #   PUT /projects/:id/archive
253
      post ':id/archive' do
254 255 256 257
        authorize!(:archive_project, user_project)

        user_project.archive!

258
        present user_project, with: Entities::Project
259 260 261 262 263 264 265 266
      end

      # Unarchive project
      #
      # Parameters:
      #   id (required) - The ID of a project
      # Example Request:
      #   PUT /projects/:id/unarchive
267
      post ':id/unarchive' do
268 269 270 271
        authorize!(:archive_project, user_project)

        user_project.unarchive!

272
        present user_project, with: Entities::Project
273 274
      end

275 276 277 278 279 280 281
      # Star project
      #
      # Parameters:
      #   id (required) - The ID of a project
      # Example Request:
      #   POST /projects/:id/star
      post ':id/star' do
282 283 284
        if current_user.starred?(user_project)
          not_modified!
        else
285 286
          current_user.toggle_star(user_project)
          user_project.reload
287

288 289 290 291 292 293 294 295 296
          present user_project, with: Entities::Project
        end
      end

      # Unstar project
      #
      # Parameters:
      #   id (required) - The ID of a project
      # Example Request:
297
      #   DELETE /projects/:id/star
298
      delete ':id/star' do
299 300 301
        if current_user.starred?(user_project)
          current_user.toggle_star(user_project)
          user_project.reload
302

303 304 305 306 307 308
          present user_project, with: Entities::Project
        else
          not_modified!
        end
      end

309 310 311 312 313 314 315 316
      # Remove project
      #
      # Parameters:
      #   id (required) - The ID of a project
      # Example Request:
      #   DELETE /projects/:id
      delete ":id" do
        authorize! :remove_project, user_project
317
        ::Projects::DestroyService.new(user_project, current_user, {}).pending_delete!
318
      end
Angus MacArthur committed
319

320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
      # Mark this project as forked from another
      #
      # Parameters:
      #   id: (required) - The ID of the project being marked as a fork
      #   forked_from_id: (required) - The ID of the project it was forked from
      # Example Request:
      #   POST /projects/:id/fork/:forked_from_id
      post ":id/fork/:forked_from_id" do
        authenticated_as_admin!
        forked_from_project = find_project(params[:forked_from_id])
        unless forked_from_project.nil?
          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
        else
337
          not_found!("Source Project")
338 339 340 341 342 343 344
        end

      end

      # Remove a forked_from relationship
      #
      # Parameters:
345
      #   id: (required) - The ID of the project being marked as a fork
346 347 348
      # Example Request:
      #  DELETE /projects/:id/fork
      delete ":id/fork" do
349
        authorize! :remove_fork_project, user_project
350
        if user_project.forked?
351 352 353
          user_project.forked_project_link.destroy
        end
      end
354

355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
      # Share project with group
      #
      # Parameters:
      #   id (required) - The ID of a project
      #   group_id (required) - The ID of a group
      #   group_access (required) - Level of permissions for sharing
      #
      # Example Request:
      #   POST /projects/:id/share
      post ":id/share" do
        authorize! :admin_project, user_project
        required_attributes! [:group_id, :group_access]

        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
        link.group_id = params[:group_id]
        link.group_access = params[:group_access]
        if link.save
          present link, with: Entities::ProjectGroupLink
        else
          render_api_error!(link.errors.full_messages.first, 409)
        end
      end

382 383 384 385 386 387 388 389 390
      # Upload a file
      #
      # Parameters:
      #   id: (required) - The ID of the project
      #   file: (required) - The file to be uploaded
      post ":id/uploads" do
        ::Projects::UploadService.new(user_project, params[:file]).execute
      end

391 392 393 394
      # search for projects current_user has access to
      #
      # Parameters:
      #   query (required) - A string contained in the project name
395 396
      #   per_page (optional) - number of projects to return per page
      #   page (optional) - the page to retrieve
397 398 399 400
      # Example Request:
      #   GET /projects/search/:query
      get "/search/:query" do
        ids = current_user.authorized_projects.map(&:id)
401 402
        visibility_levels = [ Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC ]
        projects = Project.where("(id in (?) OR visibility_level in (?)) AND (name LIKE (?))", ids, visibility_levels, "%#{params[:query]}%")
403
        sort = params[:sort] == 'desc' ? 'desc' : 'asc'
404 405

        projects = case params["order_by"]
406 407 408 409 410
                   when 'id' then projects.order("id #{sort}")
                   when 'name' then projects.order("name #{sort}")
                   when 'created_at' then projects.order("created_at #{sort}")
                   when 'last_activity_at' then projects.order("last_activity_at #{sort}")
                   else projects
411 412
                   end

413
        present paginate(projects), with: Entities::Project
414
      end
415 416 417 418 419 420 421 422 423 424


      # Get a users list
      #
      # Example Request:
      #  GET /users
      get ':id/users' do
        @users = User.where(id: user_project.team.users.map(&:id))
        @users = @users.search(params[:search]) if params[:search].present?
        @users = paginate @users
425
        present @users, with: Entities::UserBasic
426
      end
427 428 429
    end
  end
end