From f374789fe22b6fdb83e727c7c0b0a344ccb98c36 Mon Sep 17 00:00:00 2001
From: Nils Dralle <nils.91@googlemail.com>
Date: Mon, 14 Jun 2021 20:30:35 +0200
Subject: [PATCH] Fix private repo permission problem (#16142)

* Change user access permission

* Add string 'transfer_notices_3'

* Add 3rd transfer note to transfer dialog

* Add test

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
---
 options/locale/locale_en-US.ini      |  1 +
 services/repository/transfer.go      | 14 ++++++++++++++
 services/repository/transfer_test.go | 21 +++++++++++++++++++++
 templates/repo/settings/options.tmpl |  3 ++-
 4 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index c6d8d1f612..cc678e1a73 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1625,6 +1625,7 @@ settings.transfer_form_title = Enter the repository name as confirmation:
 settings.transfer_in_progress = There is currently an ongoing transfer. Please cancel it if you will like to transfer this repository to another user.
 settings.transfer_notices_1 = - You will lose access to the repository if you transfer it to an individual user.
 settings.transfer_notices_2 = - You will keep access to the repository if you transfer it to an organization that you (co-)own.
+settings.transfer_notices_3 = - If the repository is private and is transferred to an individual user, this action makes sure that the user does have at least read permission (and changes permissions if necessary).
 settings.transfer_owner = New Owner
 settings.transfer_perform = Perform Transfer
 settings.transfer_started = This repository has been marked for transfer and awaits confirmation from "%s"
diff --git a/services/repository/transfer.go b/services/repository/transfer.go
index ec769190bd..bb323c1c0a 100644
--- a/services/repository/transfer.go
+++ b/services/repository/transfer.go
@@ -94,6 +94,20 @@ func StartRepositoryTransfer(doer, newOwner *models.User, repo *models.Repositor
 		}
 	}
 
+	// In case the new owner would not have sufficient access to the repo, give access rights for read
+	hasAccess, err := models.HasAccess(newOwner.ID, repo)
+	if err != nil {
+		return err
+	}
+	if !hasAccess {
+		if err := repo.AddCollaborator(newOwner); err != nil {
+			return err
+		}
+		if err := repo.ChangeCollaborationAccessMode(newOwner.ID, models.AccessModeRead); err != nil {
+			return err
+		}
+	}
+
 	// Make repo as pending for transfer
 	repo.Status = models.RepositoryPendingTransfer
 	if err := models.CreatePendingRepositoryTransfer(doer, newOwner, repo.ID, teams); err != nil {
diff --git a/services/repository/transfer_test.go b/services/repository/transfer_test.go
index 052b8c9954..c92844674c 100644
--- a/services/repository/transfer_test.go
+++ b/services/repository/transfer_test.go
@@ -52,3 +52,24 @@ func TestTransferOwnership(t *testing.T) {
 
 	models.CheckConsistencyFor(t, &models.Repository{}, &models.User{}, &models.Team{})
 }
+
+func TestStartRepositoryTransferSetPermission(t *testing.T) {
+	assert.NoError(t, models.PrepareTestDatabase())
+
+	doer := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)
+	recipient := models.AssertExistsAndLoadBean(t, &models.User{ID: 5}).(*models.User)
+	repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository)
+	repo.Owner = models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
+
+	hasAccess, err := models.HasAccess(recipient.ID, repo)
+	assert.NoError(t, err)
+	assert.False(t, hasAccess)
+
+	assert.NoError(t, StartRepositoryTransfer(doer, recipient, repo, nil))
+
+	hasAccess, err = models.HasAccess(recipient.ID, repo)
+	assert.NoError(t, err)
+	assert.True(t, hasAccess)
+
+	models.CheckConsistencyFor(t, &models.Repository{}, &models.User{}, &models.Team{})
+}
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl
index 163a1a66d2..eb76a3b720 100644
--- a/templates/repo/settings/options.tmpl
+++ b/templates/repo/settings/options.tmpl
@@ -733,7 +733,8 @@
 		<div class="content">
 			<div class="ui warning message text left">
 				{{.i18n.Tr "repo.settings.transfer_notices_1"}} <br>
-				{{.i18n.Tr "repo.settings.transfer_notices_2"}}
+				{{.i18n.Tr "repo.settings.transfer_notices_2"}} <br>
+				{{.i18n.Tr "repo.settings.transfer_notices_3"}}
 			</div>
 			<form class="ui form" action="{{.Link}}" method="post">
 				{{.CsrfTokenHtml}}