diff --git a/app/models/namespace.rb b/app/models/namespace.rb index dea34e812ca..8638c5a9c53 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -51,6 +51,7 @@ class Namespace < ApplicationRecord validate :nesting_level_allowed delegate :name, to: :owner, allow_nil: true, prefix: true + delegate :avatar_url, to: :owner, allow_nil: true after_commit :refresh_access_of_projects_invited_groups, on: :update, if: -> { previous_changes.key?('share_with_group_lock') } @@ -149,6 +150,10 @@ class Namespace < ApplicationRecord type == 'Group' ? 'group' : 'user' end + def user? + kind == 'user' + end + def find_fork_of(project) return unless project.fork_network diff --git a/doc/api/projects.md b/doc/api/projects.md index 0a950352ecf..951961e45ff 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -494,7 +494,9 @@ GET /projects/:id "name": "Diaspora", "path": "diaspora", "kind": "group", - "full_path": "diaspora" + "full_path": "diaspora", + "avatar_url": "http://localhost:3000/uploads/group/avatar/3/foo.jpg", + "web_url": "http://localhost:3000/groups/diaspora" }, "import_status": "none", "import_error": null, @@ -561,6 +563,8 @@ GET /projects/:id } ``` +**Note**: The `web_url` and `avatar_url` attributes on `namespace` were [introduced][ce-27427] in GitLab 11.11. + If the project is a fork, and you provide a valid token to authenticate, the `forked_from_project` field will appear in the response. @@ -1587,3 +1591,4 @@ GET /projects/:id/snapshot [eep]: https://about.gitlab.com/pricing/ "Available only in GitLab Premium" [ee-6137]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6137 +[ce-27427]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27427 diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 4bdac278add..ee8480122c4 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -922,7 +922,15 @@ module API end class NamespaceBasic < Grape::Entity - expose :id, :name, :path, :kind, :full_path, :parent_id + expose :id, :name, :path, :kind, :full_path, :parent_id, :avatar_url + + expose :web_url do |namespace| + if namespace.user? + Gitlab::Routing.url_helpers.user_url(namespace.owner) + else + namespace.web_url + end + end end class Namespace < NamespaceBasic diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 387d1221c76..95a4b0f6d71 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -63,6 +63,11 @@ describe Namespace do end end + describe 'delegate' do + it { is_expected.to delegate_method(:name).to(:owner).with_prefix.with_arguments(allow_nil: true) } + it { is_expected.to delegate_method(:avatar_url).to(:owner).with_arguments(allow_nil: true) } + end + describe "Respond to" do it { is_expected.to respond_to(:human_name) } it { is_expected.to respond_to(:to_param) } @@ -801,4 +806,21 @@ describe Namespace do end end end + + describe '#user?' do + subject { namespace.user? } + + context 'when type is a user' do + let(:user) { create(:user) } + let(:namespace) { user.namespace } + + it { is_expected.to be_truthy } + end + + context 'when type is a group' do + let(:namespace) { create(:group) } + + it { is_expected.to be_falsy } + end + end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 352ea448c00..577f61ae8d0 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1047,7 +1047,6 @@ describe API::Projects do expect(json_response['http_url_to_repo']).to be_present expect(json_response['web_url']).to be_present expect(json_response['owner']).to be_a Hash - expect(json_response['owner']).to be_a Hash expect(json_response['name']).to eq(project.name) expect(json_response['path']).to be_present expect(json_response['issues_enabled']).to be_present @@ -1135,7 +1134,9 @@ describe API::Projects do 'path' => user.namespace.path, 'kind' => user.namespace.kind, 'full_path' => user.namespace.full_path, - 'parent_id' => nil + 'parent_id' => nil, + 'avatar_url' => user.avatar_url, + 'web_url' => Gitlab::Routing.url_helpers.user_url(user) }) end @@ -1337,6 +1338,37 @@ describe API::Projects do end end end + + context 'when project belongs to a group namespace' do + let(:group) { create(:group, :with_avatar) } + let(:project) { create(:project, namespace: group) } + let!(:project_member) { create(:project_member, :developer, user: user, project: project) } + + it 'returns group web_url and avatar_url' do + get api("/projects/#{project.id}", user) + + expect(response).to have_gitlab_http_status(200) + + group_data = json_response['namespace'] + expect(group_data['web_url']).to eq(group.web_url) + expect(group_data['avatar_url']).to eq(group.avatar_url) + end + end + + context 'when project belongs to a user namespace' do + let(:user) { create(:user) } + let(:project) { create(:project, namespace: user.namespace) } + + it 'returns user web_url and avatar_url' do + get api("/projects/#{project.id}", user) + + expect(response).to have_gitlab_http_status(200) + + user_data = json_response['namespace'] + expect(user_data['web_url']).to eq("http://localhost/#{user.username}") + expect(user_data['avatar_url']).to eq(user.avatar_url) + end + end end context 'with external authorization' do