mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	Add API to query collaborators permission for a repository (#18761)
Targeting #14936, #15332 Adds a collaborator permissions API endpoint according to GitHub API: https://docs.github.com/en/rest/collaborators/collaborators#get-repository-permissions-for-a-user to retrieve a collaborators permissions for a specific repository. ### Checks the repository permissions of a collaborator. `GET` `/repos/{owner}/{repo}/collaborators/{collaborator}/permission` Possible `permission` values are `admin`, `write`, `read`, `owner`, `none`. ```json { "permission": "admin", "role_name": "admin", "user": {} } ``` Where `permission` and `role_name` hold the same `permission` value and `user` is filled with the user API object. Only admins are allowed to use this API endpoint.
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							e5c6c001c5
						
					
				
				
					commit
					ad6d08d155
				
			
							
								
								
									
										131
									
								
								integrations/api_repo_collaborator_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								integrations/api_repo_collaborator_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package integrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models/perm"
 | 
				
			||||||
 | 
						repo_model "code.gitea.io/gitea/models/repo"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models/unittest"
 | 
				
			||||||
 | 
						user_model "code.gitea.io/gitea/models/user"
 | 
				
			||||||
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestAPIRepoCollaboratorPermission(t *testing.T) {
 | 
				
			||||||
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
 | 
				
			||||||
 | 
							repo2Owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo2.OwnerID}).(*user_model.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
 | 
				
			||||||
 | 
							user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
 | 
				
			||||||
 | 
							user10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}).(*user_model.User)
 | 
				
			||||||
 | 
							user11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 11}).(*user_model.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							session := loginUser(t, repo2Owner.Name)
 | 
				
			||||||
 | 
							testCtx := NewAPITestContext(t, repo2Owner.Name, repo2.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("RepoOwnerShouldBeOwner", func(t *testing.T) {
 | 
				
			||||||
 | 
								req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, repo2Owner.Name, testCtx.Token)
 | 
				
			||||||
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var repoPermission api.RepoCollaboratorPermission
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &repoPermission)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								assert.Equal(t, "owner", repoPermission.Permission)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("CollaboratorWithReadAccess", func(t *testing.T) {
 | 
				
			||||||
 | 
								t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeRead))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user4.Name, testCtx.Token)
 | 
				
			||||||
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var repoPermission api.RepoCollaboratorPermission
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &repoPermission)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								assert.Equal(t, "read", repoPermission.Permission)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("CollaboratorWithWriteAccess", func(t *testing.T) {
 | 
				
			||||||
 | 
								t.Run("AddUserAsCollaboratorWithWriteAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeWrite))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user4.Name, testCtx.Token)
 | 
				
			||||||
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var repoPermission api.RepoCollaboratorPermission
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &repoPermission)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								assert.Equal(t, "write", repoPermission.Permission)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("CollaboratorWithAdminAccess", func(t *testing.T) {
 | 
				
			||||||
 | 
								t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeAdmin))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user4.Name, testCtx.Token)
 | 
				
			||||||
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var repoPermission api.RepoCollaboratorPermission
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &repoPermission)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								assert.Equal(t, "admin", repoPermission.Permission)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("CollaboratorNotFound", func(t *testing.T) {
 | 
				
			||||||
 | 
								req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, "non-existent-user", testCtx.Token)
 | 
				
			||||||
 | 
								session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) {
 | 
				
			||||||
 | 
								t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								_session := loginUser(t, user5.Name)
 | 
				
			||||||
 | 
								_testCtx := NewAPITestContext(t, user5.Name, repo2.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user5.Name, _testCtx.Token)
 | 
				
			||||||
 | 
								resp := _session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var repoPermission api.RepoCollaboratorPermission
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &repoPermission)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								assert.Equal(t, "read", repoPermission.Permission)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) {
 | 
				
			||||||
 | 
								t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								_session := loginUser(t, user5.Name)
 | 
				
			||||||
 | 
								_testCtx := NewAPITestContext(t, user5.Name, repo2.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user5.Name, _testCtx.Token)
 | 
				
			||||||
 | 
								resp := _session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var repoPermission api.RepoCollaboratorPermission
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &repoPermission)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								assert.Equal(t, "read", repoPermission.Permission)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("RepoAdminCanQueryACollaboratorsPermissions", func(t *testing.T) {
 | 
				
			||||||
 | 
								t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user10.Name, perm.AccessModeAdmin))
 | 
				
			||||||
 | 
								t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user11.Name, perm.AccessModeRead))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								_session := loginUser(t, user10.Name)
 | 
				
			||||||
 | 
								_testCtx := NewAPITestContext(t, user10.Name, repo2.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user11.Name, _testCtx.Token)
 | 
				
			||||||
 | 
								resp := _session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var repoPermission api.RepoCollaboratorPermission
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &repoPermission)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								assert.Equal(t, "read", repoPermission.Permission)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,6 +4,7 @@
 | 
				
			|||||||
  id: 1
 | 
					  id: 1
 | 
				
			||||||
  lower_name: user1
 | 
					  lower_name: user1
 | 
				
			||||||
  name: user1
 | 
					  name: user1
 | 
				
			||||||
 | 
					  login_name: user1
 | 
				
			||||||
  full_name: User One
 | 
					  full_name: User One
 | 
				
			||||||
  email: user1@example.com
 | 
					  email: user1@example.com
 | 
				
			||||||
  email_notifications_preference: enabled
 | 
					  email_notifications_preference: enabled
 | 
				
			||||||
@@ -21,6 +22,7 @@
 | 
				
			|||||||
  id: 2
 | 
					  id: 2
 | 
				
			||||||
  lower_name: user2
 | 
					  lower_name: user2
 | 
				
			||||||
  name: user2
 | 
					  name: user2
 | 
				
			||||||
 | 
					  login_name: user2
 | 
				
			||||||
  full_name: "   < U<se>r Tw<o > ><  "
 | 
					  full_name: "   < U<se>r Tw<o > ><  "
 | 
				
			||||||
  email: user2@example.com
 | 
					  email: user2@example.com
 | 
				
			||||||
  keep_email_private: true
 | 
					  keep_email_private: true
 | 
				
			||||||
@@ -42,6 +44,7 @@
 | 
				
			|||||||
  id: 3
 | 
					  id: 3
 | 
				
			||||||
  lower_name: user3
 | 
					  lower_name: user3
 | 
				
			||||||
  name: user3
 | 
					  name: user3
 | 
				
			||||||
 | 
					  login_name: user3
 | 
				
			||||||
  full_name: " <<<< >> >> > >> > >>> >> "
 | 
					  full_name: " <<<< >> >> > >> > >>> >> "
 | 
				
			||||||
  email: user3@example.com
 | 
					  email: user3@example.com
 | 
				
			||||||
  email_notifications_preference: onmention
 | 
					  email_notifications_preference: onmention
 | 
				
			||||||
@@ -60,6 +63,7 @@
 | 
				
			|||||||
  id: 4
 | 
					  id: 4
 | 
				
			||||||
  lower_name: user4
 | 
					  lower_name: user4
 | 
				
			||||||
  name: user4
 | 
					  name: user4
 | 
				
			||||||
 | 
					  login_name: user4
 | 
				
			||||||
  full_name: "          "
 | 
					  full_name: "          "
 | 
				
			||||||
  email: user4@example.com
 | 
					  email: user4@example.com
 | 
				
			||||||
  email_notifications_preference: onmention
 | 
					  email_notifications_preference: onmention
 | 
				
			||||||
@@ -78,6 +82,7 @@
 | 
				
			|||||||
  id: 5
 | 
					  id: 5
 | 
				
			||||||
  lower_name: user5
 | 
					  lower_name: user5
 | 
				
			||||||
  name: user5
 | 
					  name: user5
 | 
				
			||||||
 | 
					  login_name: user5
 | 
				
			||||||
  full_name: User Five
 | 
					  full_name: User Five
 | 
				
			||||||
  email: user5@example.com
 | 
					  email: user5@example.com
 | 
				
			||||||
  email_notifications_preference: enabled
 | 
					  email_notifications_preference: enabled
 | 
				
			||||||
@@ -97,6 +102,7 @@
 | 
				
			|||||||
  id: 6
 | 
					  id: 6
 | 
				
			||||||
  lower_name: user6
 | 
					  lower_name: user6
 | 
				
			||||||
  name: user6
 | 
					  name: user6
 | 
				
			||||||
 | 
					  login_name: user6
 | 
				
			||||||
  full_name: User Six
 | 
					  full_name: User Six
 | 
				
			||||||
  email: user6@example.com
 | 
					  email: user6@example.com
 | 
				
			||||||
  email_notifications_preference: enabled
 | 
					  email_notifications_preference: enabled
 | 
				
			||||||
@@ -115,6 +121,7 @@
 | 
				
			|||||||
  id: 7
 | 
					  id: 7
 | 
				
			||||||
  lower_name: user7
 | 
					  lower_name: user7
 | 
				
			||||||
  name: user7
 | 
					  name: user7
 | 
				
			||||||
 | 
					  login_name: user7
 | 
				
			||||||
  full_name: User Seven
 | 
					  full_name: User Seven
 | 
				
			||||||
  email: user7@example.com
 | 
					  email: user7@example.com
 | 
				
			||||||
  email_notifications_preference: disabled
 | 
					  email_notifications_preference: disabled
 | 
				
			||||||
@@ -133,6 +140,7 @@
 | 
				
			|||||||
  id: 8
 | 
					  id: 8
 | 
				
			||||||
  lower_name: user8
 | 
					  lower_name: user8
 | 
				
			||||||
  name: user8
 | 
					  name: user8
 | 
				
			||||||
 | 
					  login_name: user8
 | 
				
			||||||
  full_name: User Eight
 | 
					  full_name: User Eight
 | 
				
			||||||
  email: user8@example.com
 | 
					  email: user8@example.com
 | 
				
			||||||
  email_notifications_preference: enabled
 | 
					  email_notifications_preference: enabled
 | 
				
			||||||
@@ -152,6 +160,7 @@
 | 
				
			|||||||
  id: 9
 | 
					  id: 9
 | 
				
			||||||
  lower_name: user9
 | 
					  lower_name: user9
 | 
				
			||||||
  name: user9
 | 
					  name: user9
 | 
				
			||||||
 | 
					  login_name: user9
 | 
				
			||||||
  full_name: User Nine
 | 
					  full_name: User Nine
 | 
				
			||||||
  email: user9@example.com
 | 
					  email: user9@example.com
 | 
				
			||||||
  email_notifications_preference: onmention
 | 
					  email_notifications_preference: onmention
 | 
				
			||||||
@@ -169,6 +178,7 @@
 | 
				
			|||||||
  id: 10
 | 
					  id: 10
 | 
				
			||||||
  lower_name: user10
 | 
					  lower_name: user10
 | 
				
			||||||
  name: user10
 | 
					  name: user10
 | 
				
			||||||
 | 
					  login_name: user10
 | 
				
			||||||
  full_name: User Ten
 | 
					  full_name: User Ten
 | 
				
			||||||
  email: user10@example.com
 | 
					  email: user10@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -185,6 +195,7 @@
 | 
				
			|||||||
  id: 11
 | 
					  id: 11
 | 
				
			||||||
  lower_name: user11
 | 
					  lower_name: user11
 | 
				
			||||||
  name: user11
 | 
					  name: user11
 | 
				
			||||||
 | 
					  login_name: user11
 | 
				
			||||||
  full_name: User Eleven
 | 
					  full_name: User Eleven
 | 
				
			||||||
  email: user11@example.com
 | 
					  email: user11@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -201,6 +212,7 @@
 | 
				
			|||||||
  id: 12
 | 
					  id: 12
 | 
				
			||||||
  lower_name: user12
 | 
					  lower_name: user12
 | 
				
			||||||
  name: user12
 | 
					  name: user12
 | 
				
			||||||
 | 
					  login_name: user12
 | 
				
			||||||
  full_name: User 12
 | 
					  full_name: User 12
 | 
				
			||||||
  email: user12@example.com
 | 
					  email: user12@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -217,6 +229,7 @@
 | 
				
			|||||||
  id: 13
 | 
					  id: 13
 | 
				
			||||||
  lower_name: user13
 | 
					  lower_name: user13
 | 
				
			||||||
  name: user13
 | 
					  name: user13
 | 
				
			||||||
 | 
					  login_name: user13
 | 
				
			||||||
  full_name: User 13
 | 
					  full_name: User 13
 | 
				
			||||||
  email: user13@example.com
 | 
					  email: user13@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -233,6 +246,7 @@
 | 
				
			|||||||
  id: 14
 | 
					  id: 14
 | 
				
			||||||
  lower_name: user14
 | 
					  lower_name: user14
 | 
				
			||||||
  name: user14
 | 
					  name: user14
 | 
				
			||||||
 | 
					  login_name: user14
 | 
				
			||||||
  full_name: User 14
 | 
					  full_name: User 14
 | 
				
			||||||
  email: user14@example.com
 | 
					  email: user14@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -249,6 +263,7 @@
 | 
				
			|||||||
  id: 15
 | 
					  id: 15
 | 
				
			||||||
  lower_name: user15
 | 
					  lower_name: user15
 | 
				
			||||||
  name: user15
 | 
					  name: user15
 | 
				
			||||||
 | 
					  login_name: user15
 | 
				
			||||||
  full_name: User 15
 | 
					  full_name: User 15
 | 
				
			||||||
  email: user15@example.com
 | 
					  email: user15@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -265,6 +280,7 @@
 | 
				
			|||||||
  id: 16
 | 
					  id: 16
 | 
				
			||||||
  lower_name: user16
 | 
					  lower_name: user16
 | 
				
			||||||
  name: user16
 | 
					  name: user16
 | 
				
			||||||
 | 
					  login_name: user16
 | 
				
			||||||
  full_name: User 16
 | 
					  full_name: User 16
 | 
				
			||||||
  email: user16@example.com
 | 
					  email: user16@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -281,6 +297,7 @@
 | 
				
			|||||||
  id: 17
 | 
					  id: 17
 | 
				
			||||||
  lower_name: user17
 | 
					  lower_name: user17
 | 
				
			||||||
  name: user17
 | 
					  name: user17
 | 
				
			||||||
 | 
					  login_name: user17
 | 
				
			||||||
  full_name: User 17
 | 
					  full_name: User 17
 | 
				
			||||||
  email: user17@example.com
 | 
					  email: user17@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -299,6 +316,7 @@
 | 
				
			|||||||
  id: 18
 | 
					  id: 18
 | 
				
			||||||
  lower_name: user18
 | 
					  lower_name: user18
 | 
				
			||||||
  name: user18
 | 
					  name: user18
 | 
				
			||||||
 | 
					  login_name: user18
 | 
				
			||||||
  full_name: User 18
 | 
					  full_name: User 18
 | 
				
			||||||
  email: user18@example.com
 | 
					  email: user18@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -315,6 +333,7 @@
 | 
				
			|||||||
  id: 19
 | 
					  id: 19
 | 
				
			||||||
  lower_name: user19
 | 
					  lower_name: user19
 | 
				
			||||||
  name: user19
 | 
					  name: user19
 | 
				
			||||||
 | 
					  login_name: user19
 | 
				
			||||||
  full_name: User 19
 | 
					  full_name: User 19
 | 
				
			||||||
  email: user19@example.com
 | 
					  email: user19@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -333,6 +352,7 @@
 | 
				
			|||||||
  id: 20
 | 
					  id: 20
 | 
				
			||||||
  lower_name: user20
 | 
					  lower_name: user20
 | 
				
			||||||
  name: user20
 | 
					  name: user20
 | 
				
			||||||
 | 
					  login_name: user20
 | 
				
			||||||
  full_name: User 20
 | 
					  full_name: User 20
 | 
				
			||||||
  email: user20@example.com
 | 
					  email: user20@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -349,6 +369,7 @@
 | 
				
			|||||||
  id: 21
 | 
					  id: 21
 | 
				
			||||||
  lower_name: user21
 | 
					  lower_name: user21
 | 
				
			||||||
  name: user21
 | 
					  name: user21
 | 
				
			||||||
 | 
					  login_name: user21
 | 
				
			||||||
  full_name: User 21
 | 
					  full_name: User 21
 | 
				
			||||||
  email: user21@example.com
 | 
					  email: user21@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -365,6 +386,7 @@
 | 
				
			|||||||
  id: 22
 | 
					  id: 22
 | 
				
			||||||
  lower_name: limited_org
 | 
					  lower_name: limited_org
 | 
				
			||||||
  name: limited_org
 | 
					  name: limited_org
 | 
				
			||||||
 | 
					  login_name: limited_org
 | 
				
			||||||
  full_name: Limited Org
 | 
					  full_name: Limited Org
 | 
				
			||||||
  email: limited_org@example.com
 | 
					  email: limited_org@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -384,6 +406,7 @@
 | 
				
			|||||||
  id: 23
 | 
					  id: 23
 | 
				
			||||||
  lower_name: privated_org
 | 
					  lower_name: privated_org
 | 
				
			||||||
  name: privated_org
 | 
					  name: privated_org
 | 
				
			||||||
 | 
					  login_name: privated_org
 | 
				
			||||||
  full_name: Privated Org
 | 
					  full_name: Privated Org
 | 
				
			||||||
  email: privated_org@example.com
 | 
					  email: privated_org@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -403,6 +426,7 @@
 | 
				
			|||||||
  id: 24
 | 
					  id: 24
 | 
				
			||||||
  lower_name: user24
 | 
					  lower_name: user24
 | 
				
			||||||
  name: user24
 | 
					  name: user24
 | 
				
			||||||
 | 
					  login_name: user24
 | 
				
			||||||
  full_name: "user24"
 | 
					  full_name: "user24"
 | 
				
			||||||
  email: user24@example.com
 | 
					  email: user24@example.com
 | 
				
			||||||
  keep_email_private: true
 | 
					  keep_email_private: true
 | 
				
			||||||
@@ -423,6 +447,7 @@
 | 
				
			|||||||
  id: 25
 | 
					  id: 25
 | 
				
			||||||
  lower_name: org25
 | 
					  lower_name: org25
 | 
				
			||||||
  name: org25
 | 
					  name: org25
 | 
				
			||||||
 | 
					  login_name: org25
 | 
				
			||||||
  full_name: "org25"
 | 
					  full_name: "org25"
 | 
				
			||||||
  email: org25@example.com
 | 
					  email: org25@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -440,6 +465,7 @@
 | 
				
			|||||||
  id: 26
 | 
					  id: 26
 | 
				
			||||||
  lower_name: org26
 | 
					  lower_name: org26
 | 
				
			||||||
  name: org26
 | 
					  name: org26
 | 
				
			||||||
 | 
					  login_name: org26
 | 
				
			||||||
  full_name: "Org26"
 | 
					  full_name: "Org26"
 | 
				
			||||||
  email: org26@example.com
 | 
					  email: org26@example.com
 | 
				
			||||||
  email_notifications_preference: onmention
 | 
					  email_notifications_preference: onmention
 | 
				
			||||||
@@ -459,6 +485,7 @@
 | 
				
			|||||||
  id: 27
 | 
					  id: 27
 | 
				
			||||||
  lower_name: user27
 | 
					  lower_name: user27
 | 
				
			||||||
  name: user27
 | 
					  name: user27
 | 
				
			||||||
 | 
					  login_name: user27
 | 
				
			||||||
  full_name: User Twenty-Seven
 | 
					  full_name: User Twenty-Seven
 | 
				
			||||||
  email: user27@example.com
 | 
					  email: user27@example.com
 | 
				
			||||||
  email_notifications_preference: enabled
 | 
					  email_notifications_preference: enabled
 | 
				
			||||||
@@ -475,6 +502,7 @@
 | 
				
			|||||||
  id: 28
 | 
					  id: 28
 | 
				
			||||||
  lower_name: user28
 | 
					  lower_name: user28
 | 
				
			||||||
  name: user28
 | 
					  name: user28
 | 
				
			||||||
 | 
					  login_name: user28
 | 
				
			||||||
  full_name: "user27"
 | 
					  full_name: "user27"
 | 
				
			||||||
  email: user28@example.com
 | 
					  email: user28@example.com
 | 
				
			||||||
  keep_email_private: true
 | 
					  keep_email_private: true
 | 
				
			||||||
@@ -495,6 +523,7 @@
 | 
				
			|||||||
  id: 29
 | 
					  id: 29
 | 
				
			||||||
  lower_name: user29
 | 
					  lower_name: user29
 | 
				
			||||||
  name: user29
 | 
					  name: user29
 | 
				
			||||||
 | 
					  login_name: user29
 | 
				
			||||||
  full_name: User 29
 | 
					  full_name: User 29
 | 
				
			||||||
  email: user29@example.com
 | 
					  email: user29@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -512,6 +541,7 @@
 | 
				
			|||||||
  id: 30
 | 
					  id: 30
 | 
				
			||||||
  lower_name: user30
 | 
					  lower_name: user30
 | 
				
			||||||
  name: user30
 | 
					  name: user30
 | 
				
			||||||
 | 
					  login_name: user30
 | 
				
			||||||
  full_name: User Thirty
 | 
					  full_name: User Thirty
 | 
				
			||||||
  email: user30@example.com
 | 
					  email: user30@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -530,6 +560,7 @@
 | 
				
			|||||||
  id: 31
 | 
					  id: 31
 | 
				
			||||||
  lower_name: user31
 | 
					  lower_name: user31
 | 
				
			||||||
  name: user31
 | 
					  name: user31
 | 
				
			||||||
 | 
					  login_name: user31
 | 
				
			||||||
  full_name: "user31"
 | 
					  full_name: "user31"
 | 
				
			||||||
  email: user31@example.com
 | 
					  email: user31@example.com
 | 
				
			||||||
  passwd_hash_algo: argon2
 | 
					  passwd_hash_algo: argon2
 | 
				
			||||||
@@ -547,6 +578,7 @@
 | 
				
			|||||||
  id: 32
 | 
					  id: 32
 | 
				
			||||||
  lower_name: user32
 | 
					  lower_name: user32
 | 
				
			||||||
  name: user32
 | 
					  name: user32
 | 
				
			||||||
 | 
					  login_name: user32
 | 
				
			||||||
  full_name: User 32 (U2F test)
 | 
					  full_name: User 32 (U2F test)
 | 
				
			||||||
  email: user32@example.com
 | 
					  email: user32@example.com
 | 
				
			||||||
  passwd: 7d93daa0d1e6f2305cc8fa496847d61dc7320bb16262f9c55dd753480207234cdd96a93194e408341971742f4701772a025a # password
 | 
					  passwd: 7d93daa0d1e6f2305cc8fa496847d61dc7320bb16262f9c55dd753480207234cdd96a93194e408341971742f4701772a025a # password
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,3 +95,12 @@ func User2UserSettings(user *user_model.User) api.UserSettings {
 | 
				
			|||||||
		DiffViewStyle: user.DiffViewStyle,
 | 
							DiffViewStyle: user.DiffViewStyle,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ToUserAndPermission return User and its collaboration permission for a repository
 | 
				
			||||||
 | 
					func ToUserAndPermission(user, doer *user_model.User, accessMode perm.AccessMode) api.RepoCollaboratorPermission {
 | 
				
			||||||
 | 
						return api.RepoCollaboratorPermission{
 | 
				
			||||||
 | 
							User:       ToUser(user, doer),
 | 
				
			||||||
 | 
							Permission: accessMode.String(),
 | 
				
			||||||
 | 
							RoleName:   accessMode.String(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,3 +8,10 @@ package structs
 | 
				
			|||||||
type AddCollaboratorOption struct {
 | 
					type AddCollaboratorOption struct {
 | 
				
			||||||
	Permission *string `json:"permission"`
 | 
						Permission *string `json:"permission"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RepoCollaboratorPermission to get repository permission for a collaborator
 | 
				
			||||||
 | 
					type RepoCollaboratorPermission struct {
 | 
				
			||||||
 | 
						Permission string `json:"permission"`
 | 
				
			||||||
 | 
						RoleName   string `json:"role_name"`
 | 
				
			||||||
 | 
						User       *User  `json:"user"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -810,9 +810,12 @@ func Routes() *web.Route {
 | 
				
			|||||||
				}, reqToken(), reqAdmin(), reqWebhooksEnabled())
 | 
									}, reqToken(), reqAdmin(), reqWebhooksEnabled())
 | 
				
			||||||
				m.Group("/collaborators", func() {
 | 
									m.Group("/collaborators", func() {
 | 
				
			||||||
					m.Get("", reqAnyRepoReader(), repo.ListCollaborators)
 | 
										m.Get("", reqAnyRepoReader(), repo.ListCollaborators)
 | 
				
			||||||
					m.Combo("/{collaborator}").Get(reqAnyRepoReader(), repo.IsCollaborator).
 | 
										m.Group("/{collaborator}", func() {
 | 
				
			||||||
 | 
											m.Combo("").Get(reqAnyRepoReader(), repo.IsCollaborator).
 | 
				
			||||||
							Put(reqAdmin(), bind(api.AddCollaboratorOption{}), repo.AddCollaborator).
 | 
												Put(reqAdmin(), bind(api.AddCollaboratorOption{}), repo.AddCollaborator).
 | 
				
			||||||
							Delete(reqAdmin(), repo.DeleteCollaborator)
 | 
												Delete(reqAdmin(), repo.DeleteCollaborator)
 | 
				
			||||||
 | 
											m.Get("/permission", repo.GetRepoPermissions)
 | 
				
			||||||
 | 
										}, reqToken())
 | 
				
			||||||
				}, reqToken())
 | 
									}, reqToken())
 | 
				
			||||||
				m.Get("/assignees", reqToken(), reqAnyRepoReader(), repo.GetAssignees)
 | 
									m.Get("/assignees", reqToken(), reqAnyRepoReader(), repo.GetAssignees)
 | 
				
			||||||
				m.Get("/reviewers", reqToken(), reqAnyRepoReader(), repo.GetReviewers)
 | 
									m.Get("/reviewers", reqToken(), reqAnyRepoReader(), repo.GetReviewers)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -233,6 +233,61 @@ func DeleteCollaborator(ctx *context.APIContext) {
 | 
				
			|||||||
	ctx.Status(http.StatusNoContent)
 | 
						ctx.Status(http.StatusNoContent)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetRepoPermissions gets repository permissions for a user
 | 
				
			||||||
 | 
					func GetRepoPermissions(ctx *context.APIContext) {
 | 
				
			||||||
 | 
						// swagger:operation GET /repos/{owner}/{repo}/collaborators/{collaborator}/permission repository repoGetRepoPermissions
 | 
				
			||||||
 | 
						// ---
 | 
				
			||||||
 | 
						// summary: Get repository permissions for a user
 | 
				
			||||||
 | 
						// produces:
 | 
				
			||||||
 | 
						// - application/json
 | 
				
			||||||
 | 
						// parameters:
 | 
				
			||||||
 | 
						// - name: owner
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: owner of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: repo
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: name of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: collaborator
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: username of the collaborator
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// responses:
 | 
				
			||||||
 | 
						//   "200":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/RepoCollaboratorPermission"
 | 
				
			||||||
 | 
						//   "404":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
						//   "403":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/forbidden"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !ctx.Doer.IsAdmin && ctx.Doer.LoginName != ctx.Params(":collaborator") && !ctx.IsUserRepoAdmin() {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusForbidden, "User", "Only admins can query all permissions, repo admins can query all repo permissions, collaborators can query only their own")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						collaborator, err := user_model.GetUserByName(ctx.Params(":collaborator"))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if user_model.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
								ctx.Error(http.StatusNotFound, "GetUserByName", err)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						permission, err := models.GetUserRepoPermission(ctx, ctx.Repo.Repository, collaborator)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.JSON(http.StatusOK, convert.ToUserAndPermission(collaborator, ctx.ContextUser, permission.AccessMode))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetReviewers return all users that can be requested to review in this repo
 | 
					// GetReviewers return all users that can be requested to review in this repo
 | 
				
			||||||
func GetReviewers(ctx *context.APIContext) {
 | 
					func GetReviewers(ctx *context.APIContext) {
 | 
				
			||||||
	// swagger:operation GET /repos/{owner}/{repo}/reviewers repository repoGetReviewers
 | 
						// swagger:operation GET /repos/{owner}/{repo}/reviewers repository repoGetReviewers
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -344,3 +344,10 @@ type swaggerWikiCommitList struct {
 | 
				
			|||||||
	// in:body
 | 
						// in:body
 | 
				
			||||||
	Body api.WikiCommitList `json:"body"`
 | 
						Body api.WikiCommitList `json:"body"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RepoCollaboratorPermission
 | 
				
			||||||
 | 
					// swagger:response RepoCollaboratorPermission
 | 
				
			||||||
 | 
					type swaggerRepoCollaboratorPermission struct {
 | 
				
			||||||
 | 
						// in:body
 | 
				
			||||||
 | 
						Body api.RepoCollaboratorPermission `json:"body"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3129,6 +3129,52 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "/repos/{owner}/{repo}/collaborators/{collaborator}/permission": {
 | 
				
			||||||
 | 
					      "get": {
 | 
				
			||||||
 | 
					        "produces": [
 | 
				
			||||||
 | 
					          "application/json"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "tags": [
 | 
				
			||||||
 | 
					          "repository"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "summary": "Get repository permissions for a user",
 | 
				
			||||||
 | 
					        "operationId": "repoGetRepoPermissions",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "owner of the repo",
 | 
				
			||||||
 | 
					            "name": "owner",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "name of the repo",
 | 
				
			||||||
 | 
					            "name": "repo",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "username of the collaborator",
 | 
				
			||||||
 | 
					            "name": "collaborator",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": {
 | 
				
			||||||
 | 
					          "200": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/RepoCollaboratorPermission"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "403": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/forbidden"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "404": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "/repos/{owner}/{repo}/commits": {
 | 
					    "/repos/{owner}/{repo}/commits": {
 | 
				
			||||||
      "get": {
 | 
					      "get": {
 | 
				
			||||||
        "produces": [
 | 
					        "produces": [
 | 
				
			||||||
@@ -17451,6 +17497,24 @@
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
					      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "RepoCollaboratorPermission": {
 | 
				
			||||||
 | 
					      "description": "RepoCollaboratorPermission to get repository permission for a collaborator",
 | 
				
			||||||
 | 
					      "type": "object",
 | 
				
			||||||
 | 
					      "properties": {
 | 
				
			||||||
 | 
					        "permission": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "x-go-name": "Permission"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "role_name": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "x-go-name": "RoleName"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "user": {
 | 
				
			||||||
 | 
					          "$ref": "#/definitions/User"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "RepoCommit": {
 | 
					    "RepoCommit": {
 | 
				
			||||||
      "type": "object",
 | 
					      "type": "object",
 | 
				
			||||||
      "title": "RepoCommit contains information of a commit in the context of a repository.",
 | 
					      "title": "RepoCommit contains information of a commit in the context of a repository.",
 | 
				
			||||||
@@ -19126,6 +19190,12 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "RepoCollaboratorPermission": {
 | 
				
			||||||
 | 
					      "description": "RepoCollaboratorPermission",
 | 
				
			||||||
 | 
					      "schema": {
 | 
				
			||||||
 | 
					        "$ref": "#/definitions/RepoCollaboratorPermission"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "Repository": {
 | 
					    "Repository": {
 | 
				
			||||||
      "description": "Repository",
 | 
					      "description": "Repository",
 | 
				
			||||||
      "schema": {
 | 
					      "schema": {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user