Commit ebd2a5d0ce3877bdd6b47ad9249142dddc7863d9
Exists in
master
and in
4 other branches
Merge pull request #1387 from miks/project_users_api
Project users api
Showing
6 changed files
with
187 additions
and
0 deletions
Show diff stats
app/models/users_project.rb
| @@ -20,6 +20,23 @@ class UsersProject < ActiveRecord::Base | @@ -20,6 +20,23 @@ class UsersProject < ActiveRecord::Base | ||
| 20 | 20 | ||
| 21 | delegate :name, :email, to: :user, prefix: true | 21 | delegate :name, :email, to: :user, prefix: true |
| 22 | 22 | ||
| 23 | + def self.bulk_delete(project, user_ids) | ||
| 24 | + UsersProject.transaction do | ||
| 25 | + UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| | ||
| 26 | + users_project.delete | ||
| 27 | + end | ||
| 28 | + end | ||
| 29 | + end | ||
| 30 | + | ||
| 31 | + def self.bulk_update(project, user_ids, project_access) | ||
| 32 | + UsersProject.transaction do | ||
| 33 | + UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| | ||
| 34 | + users_project.project_access = project_access | ||
| 35 | + users_project.save | ||
| 36 | + end | ||
| 37 | + end | ||
| 38 | + end | ||
| 39 | + | ||
| 23 | def self.bulk_import(project, user_ids, project_access) | 40 | def self.bulk_import(project, user_ids, project_access) |
| 24 | UsersProject.transaction do | 41 | UsersProject.transaction do |
| 25 | user_ids.each do |user_id| | 42 | user_ids.each do |user_id| |
app/roles/team.rb
| @@ -36,4 +36,17 @@ module Team | @@ -36,4 +36,17 @@ module Team | ||
| 36 | UsersProject.bulk_import(self, users_ids, access_role) | 36 | UsersProject.bulk_import(self, users_ids, access_role) |
| 37 | self.update_repository | 37 | self.update_repository |
| 38 | end | 38 | end |
| 39 | + | ||
| 40 | + # Update multiple project users | ||
| 41 | + # to same access role by user ids | ||
| 42 | + def update_users_ids_to_role(users_ids, access_role) | ||
| 43 | + UsersProject.bulk_update(self, users_ids, access_role) | ||
| 44 | + self.update_repository | ||
| 45 | + end | ||
| 46 | + | ||
| 47 | + # Delete multiple users from project by user ids | ||
| 48 | + def delete_users_ids_from_team(users_ids) | ||
| 49 | + UsersProject.bulk_delete(self, users_ids) | ||
| 50 | + self.update_repository | ||
| 51 | + end | ||
| 39 | end | 52 | end |
doc/api/projects.md
| @@ -112,6 +112,66 @@ Parameters: | @@ -112,6 +112,66 @@ Parameters: | ||
| 112 | Will return created project with status `201 Created` on success, or `404 Not | 112 | Will return created project with status `201 Created` on success, or `404 Not |
| 113 | found` on fail. | 113 | found` on fail. |
| 114 | 114 | ||
| 115 | +## Get project users | ||
| 116 | + | ||
| 117 | +Get users and access roles for existing project | ||
| 118 | + | ||
| 119 | +``` | ||
| 120 | +GET /projects/:id/users | ||
| 121 | +``` | ||
| 122 | + | ||
| 123 | +Parameters: | ||
| 124 | + | ||
| 125 | ++ `id` (required) - The ID or code name of a project | ||
| 126 | + | ||
| 127 | +Will return users and their access roles with status `200 OK` on success, or `404 Not found` on fail. | ||
| 128 | + | ||
| 129 | +## Add project users | ||
| 130 | + | ||
| 131 | +Add users to exiting project | ||
| 132 | + | ||
| 133 | +``` | ||
| 134 | +POST /projects/:id/users | ||
| 135 | +``` | ||
| 136 | + | ||
| 137 | +Parameters: | ||
| 138 | + | ||
| 139 | ++ `id` (required) - The ID or code name of a project | ||
| 140 | ++ `user_ids` (required) - The ID list of users to add | ||
| 141 | ++ `project_access` (required) - Project access level | ||
| 142 | + | ||
| 143 | +Will return status `201 Created` on success, or `404 Not found` on fail. | ||
| 144 | + | ||
| 145 | +## Update project users access level | ||
| 146 | + | ||
| 147 | +Update existing users to specified access level | ||
| 148 | + | ||
| 149 | +``` | ||
| 150 | +PUT /projects/:id/users | ||
| 151 | +``` | ||
| 152 | + | ||
| 153 | +Parameters: | ||
| 154 | + | ||
| 155 | ++ `id` (required) - The ID or code name of a project | ||
| 156 | ++ `user_ids` (required) - The ID list of users to add | ||
| 157 | ++ `project_access` (required) - Project access level | ||
| 158 | + | ||
| 159 | +Will return status `200 OK` on success, or `404 Not found` on fail. | ||
| 160 | + | ||
| 161 | +## Delete project users | ||
| 162 | + | ||
| 163 | +Delete users from exiting project | ||
| 164 | + | ||
| 165 | +``` | ||
| 166 | +DELETE /projects/:id/users | ||
| 167 | +``` | ||
| 168 | + | ||
| 169 | +Parameters: | ||
| 170 | + | ||
| 171 | ++ `id` (required) - The ID or code name of a project | ||
| 172 | ++ `user_ids` (required) - The ID list of users to add | ||
| 173 | + | ||
| 174 | +Will return status `200 OK` on success, or `404 Not found` on fail. | ||
| 115 | 175 | ||
| 116 | ## Project repository branches | 176 | ## Project repository branches |
| 117 | 177 |
lib/api/entities.rb
| @@ -16,6 +16,11 @@ module Gitlab | @@ -16,6 +16,11 @@ module Gitlab | ||
| 16 | expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at | 16 | expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at |
| 17 | end | 17 | end |
| 18 | 18 | ||
| 19 | + class UsersProject < Grape::Entity | ||
| 20 | + expose :user, using: Entities::UserBasic | ||
| 21 | + expose :project_access | ||
| 22 | + end | ||
| 23 | + | ||
| 19 | class RepoObject < Grape::Entity | 24 | class RepoObject < Grape::Entity |
| 20 | expose :name, :commit | 25 | expose :name, :commit |
| 21 | end | 26 | end |
lib/api/projects.rb
| @@ -54,6 +54,55 @@ module Gitlab | @@ -54,6 +54,55 @@ module Gitlab | ||
| 54 | end | 54 | end |
| 55 | end | 55 | end |
| 56 | 56 | ||
| 57 | + # Get project users | ||
| 58 | + # | ||
| 59 | + # Parameters: | ||
| 60 | + # id (required) - The ID or code name of a project | ||
| 61 | + # Example Request: | ||
| 62 | + # GET /projects/:id/users | ||
| 63 | + get ":id/users" do | ||
| 64 | + @users_projects = paginate user_project.users_projects | ||
| 65 | + present @users_projects, with: Entities::UsersProject | ||
| 66 | + end | ||
| 67 | + | ||
| 68 | + # Add users to project with specified access level | ||
| 69 | + # | ||
| 70 | + # Parameters: | ||
| 71 | + # id (required) - The ID or code name of a project | ||
| 72 | + # user_ids (required) - The ID list of users to add | ||
| 73 | + # project_access (required) - Project access level | ||
| 74 | + # Example Request: | ||
| 75 | + # POST /projects/:id/users | ||
| 76 | + post ":id/users" do | ||
| 77 | + user_project.add_users_ids_to_team(params[:user_ids].values, params[:project_access]) | ||
| 78 | + nil | ||
| 79 | + end | ||
| 80 | + | ||
| 81 | + # Update users to specified access level | ||
| 82 | + # | ||
| 83 | + # Parameters: | ||
| 84 | + # id (required) - The ID or code name of a project | ||
| 85 | + # user_ids (required) - The ID list of users to add | ||
| 86 | + # project_access (required) - New project access level to | ||
| 87 | + # Example Request: | ||
| 88 | + # PUT /projects/:id/add_users | ||
| 89 | + put ":id/users" do | ||
| 90 | + user_project.update_users_ids_to_role(params[:user_ids].values, params[:project_access]) | ||
| 91 | + nil | ||
| 92 | + end | ||
| 93 | + | ||
| 94 | + # Delete project users | ||
| 95 | + # | ||
| 96 | + # Parameters: | ||
| 97 | + # id (required) - The ID or code name of a project | ||
| 98 | + # user_ids (required) - The ID list of users to delete | ||
| 99 | + # Example Request: | ||
| 100 | + # DELETE /projects/:id/users | ||
| 101 | + delete ":id/users" do | ||
| 102 | + user_project.delete_users_ids_from_team(params[:user_ids].values) | ||
| 103 | + nil | ||
| 104 | + end | ||
| 105 | + | ||
| 57 | # Get a project repository branches | 106 | # Get a project repository branches |
| 58 | # | 107 | # |
| 59 | # Parameters: | 108 | # Parameters: |
spec/requests/api/projects_spec.rb
| @@ -4,8 +4,12 @@ describe Gitlab::API do | @@ -4,8 +4,12 @@ describe Gitlab::API do | ||
| 4 | include ApiHelpers | 4 | include ApiHelpers |
| 5 | 5 | ||
| 6 | let(:user) { Factory :user } | 6 | let(:user) { Factory :user } |
| 7 | + let(:user2) { Factory.create(:user) } | ||
| 8 | + let(:user3) { Factory.create(:user) } | ||
| 7 | let!(:project) { Factory :project, owner: user } | 9 | let!(:project) { Factory :project, owner: user } |
| 8 | let!(:snippet) { Factory :snippet, author: user, project: project, title: 'example' } | 10 | let!(:snippet) { Factory :snippet, author: user, project: project, title: 'example' } |
| 11 | + let!(:users_project) { Factory :users_project, user: user, project: project, project_access: UsersProject::MASTER } | ||
| 12 | + let!(:users_project2) { Factory :users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER } | ||
| 9 | before { project.add_access(user, :read) } | 13 | before { project.add_access(user, :read) } |
| 10 | 14 | ||
| 11 | describe "GET /projects" do | 15 | describe "GET /projects" do |
| @@ -104,6 +108,45 @@ describe Gitlab::API do | @@ -104,6 +108,45 @@ describe Gitlab::API do | ||
| 104 | end | 108 | end |
| 105 | end | 109 | end |
| 106 | 110 | ||
| 111 | + describe "GET /projects/:id/users" do | ||
| 112 | + it "should return project users" do | ||
| 113 | + get api("/projects/#{project.code}/users", user) | ||
| 114 | + | ||
| 115 | + response.status.should == 200 | ||
| 116 | + | ||
| 117 | + json_response.should be_an Array | ||
| 118 | + json_response.count.should == 2 | ||
| 119 | + json_response.first['user']['id'].should == user.id | ||
| 120 | + end | ||
| 121 | + end | ||
| 122 | + | ||
| 123 | + describe "POST /projects/:id/users" do | ||
| 124 | + it "should add users to project" do | ||
| 125 | + expect { | ||
| 126 | + post api("/projects/#{project.code}/users", user), | ||
| 127 | + user_ids: {"0" => user2.id}, project_access: UsersProject::DEVELOPER | ||
| 128 | + }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(1) | ||
| 129 | + end | ||
| 130 | + end | ||
| 131 | + | ||
| 132 | + describe "PUT /projects/:id/users" do | ||
| 133 | + it "should update users to new access role" do | ||
| 134 | + expect { | ||
| 135 | + put api("/projects/#{project.code}/users", user), | ||
| 136 | + user_ids: {"0" => user3.id}, project_access: UsersProject::MASTER | ||
| 137 | + }.to change {project.users_projects.where(:project_access => UsersProject::MASTER).count}.by(1) | ||
| 138 | + end | ||
| 139 | + end | ||
| 140 | + | ||
| 141 | + describe "DELETE /projects/:id/users" do | ||
| 142 | + it "should delete users from project" do | ||
| 143 | + expect { | ||
| 144 | + delete api("/projects/#{project.code}/users", user), | ||
| 145 | + user_ids: {"0" => user3.id} | ||
| 146 | + }.to change {project.users_projects.count}.by(-1) | ||
| 147 | + end | ||
| 148 | + end | ||
| 149 | + | ||
| 107 | describe "GET /projects/:id/repository/tags" do | 150 | describe "GET /projects/:id/repository/tags" do |
| 108 | it "should return an array of project tags" do | 151 | it "should return an array of project tags" do |
| 109 | get api("/projects/#{project.code}/repository/tags", user) | 152 | get api("/projects/#{project.code}/repository/tags", user) |