diff options
-rw-r--r-- | app/models/group.rb | 6 | ||||
-rw-r--r-- | changelogs/unreleased/add-members-count-and-parent-id-data-on-namespaces-api.yml | 4 | ||||
-rw-r--r-- | doc/api/namespaces.md | 15 | ||||
-rw-r--r-- | lib/api/entities.rb | 6 | ||||
-rw-r--r-- | spec/models/namespace_spec.rb | 19 | ||||
-rw-r--r-- | spec/requests/api/namespaces_spec.rb | 16 |
6 files changed, 63 insertions, 3 deletions
diff --git a/app/models/group.rb b/app/models/group.rb index 0b93460d473..a6fdb30f84c 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -222,6 +222,12 @@ class Group < Namespace User.where(id: members_with_parents.select(:user_id)) end + def users_with_descendants + members_with_descendants = GroupMember.non_request.where(source_id: descendants.pluck(:id).push(id)) + + User.where(id: members_with_descendants.select(:user_id)) + end + def max_member_access_for_user(user) return GroupMember::OWNER if user.admin? diff --git a/changelogs/unreleased/add-members-count-and-parent-id-data-on-namespaces-api.yml b/changelogs/unreleased/add-members-count-and-parent-id-data-on-namespaces-api.yml new file mode 100644 index 00000000000..d3064a832ca --- /dev/null +++ b/changelogs/unreleased/add-members-count-and-parent-id-data-on-namespaces-api.yml @@ -0,0 +1,4 @@ +--- +title: Add "members_count" and "parent_id" data on namespaces API +merge_request: +author: diff --git a/doc/api/namespaces.md b/doc/api/namespaces.md index 4ad6071a0ed..d38a80176d9 100644 --- a/doc/api/namespaces.md +++ b/doc/api/namespaces.md @@ -29,18 +29,27 @@ Example response: { "id": 1, "path": "user1", - "kind": "user" + "kind": "user", + "full_path": "user1", + "parent_id": "null", + "members_count": "null" }, { "id": 2, "path": "group1", - "kind": "group" + "kind": "group", + "full_path": "group1", + "parent_id": "null", + "members_count": 2 + }, { "id": 3, "path": "bar", "kind": "group", "full_path": "foo/bar", + "parent_id": "9", + "members_count": 5 } ] ``` @@ -72,6 +81,8 @@ Example response: "path": "twitter", "kind": "group", "full_path": "twitter", + "parent_id": "null", + "members_count": 2 } ] ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index aa91451c9f4..2fe5280bc1c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -444,7 +444,11 @@ module API end class Namespace < Grape::Entity - expose :id, :name, :path, :kind, :full_path + expose :id, :name, :path, :kind, :full_path, :parent_id + + expose :members_count do |namespace, _| + namespace.users_with_descendants.count if namespace.kind == 'group' + end end class MemberAccess < Grape::Entity diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index e7c3acf19eb..d4f898f6d9f 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -323,6 +323,25 @@ describe Namespace, models: true do end end + describe '#users_with_descendants', :nested_groups do + let(:user_a) { create(:user) } + let(:user_b) { create(:user) } + + let(:group) { create(:group) } + let(:nested_group) { create(:group, parent: group) } + let(:deep_nested_group) { create(:group, parent: nested_group) } + + it 'returns member users on every nest level without duplication' do + group.add_developer(user_a) + nested_group.add_developer(user_b) + deep_nested_group.add_developer(user_a) + + expect(group.users_with_descendants).to contain_exactly(user_a, user_b) + expect(nested_group.users_with_descendants).to contain_exactly(user_a, user_b) + expect(deep_nested_group.users_with_descendants).to contain_exactly(user_a) + end + end + describe '#user_ids_for_project_authorizations' do it 'returns the user IDs for which to refresh authorizations' do expect(namespace.user_ids_for_project_authorizations) diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb index 3bf16a3ae27..03b1f549ce0 100644 --- a/spec/requests/api/namespaces_spec.rb +++ b/spec/requests/api/namespaces_spec.rb @@ -15,6 +15,14 @@ describe API::Namespaces do end context "when authenticated as admin" do + it "returns correct attributes" do + get api("/namespaces", admin) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response.first).to include('id', 'name', 'path', 'full_path', 'parent_id', 'members_count') + end + it "admin: returns an array of all namespaces" do get api("/namespaces", admin) @@ -37,6 +45,14 @@ describe API::Namespaces do end context "when authenticated as a regular user" do + it "returns correct attributes" do + get api("/namespaces", user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response.first).to include('id', 'name', 'path', 'full_path', 'parent_id', 'members_count') + end + it "user: returns an array of namespaces" do get api("/namespaces", user) |