From 313e6174d832501c57724ae7a6285194b7b81aab Mon Sep 17 00:00:00 2001 From: Gusted Date: Sat, 29 Jul 2023 14:00:56 +0200 Subject: [PATCH] [MODERATION] Remove blocked user collaborations with doer - When the doer blocks an user, who is also an collaborator on an repository that the doer owns, remove that collaboration. - Added unit tests. - Refactor the unit test to be more organized. (cherry picked from commit ec8701617830152680d69d50d64cb43cc2054a89) --- models/repo/collaboration.go | 13 +++++++ models/repo/collaboration_test.go | 21 ++++++++++++ services/user/block.go | 12 +++++++ services/user/block_test.go | 56 ++++++++++++++++++++++++------- 4 files changed, 90 insertions(+), 12 deletions(-) diff --git a/models/repo/collaboration.go b/models/repo/collaboration.go index 7989e5bdf9..b44e135040 100644 --- a/models/repo/collaboration.go +++ b/models/repo/collaboration.go @@ -137,6 +137,19 @@ func ChangeCollaborationAccessMode(ctx context.Context, repo *Repository, uid in }) } +// GetCollaboratorWithUser returns all collaborator IDs of collabUserID on +// repositories of ownerID. +func GetCollaboratorWithUser(ctx context.Context, ownerID, collabUserID int64) ([]int64, error) { + collabsID := make([]int64, 0, 8) + err := db.GetEngine(ctx).Table("collaboration").Select("collaboration.`id`"). + Join("INNER", "repository", "repository.id = collaboration.repo_id"). + Where("repository.`owner_id` = ?", ownerID). + And("collaboration.`user_id` = ?", collabUserID). + Find(&collabsID) + + return collabsID, err +} + // IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository func IsOwnerMemberCollaborator(repo *Repository, userID int64) (bool, error) { if repo.OwnerID == userID { diff --git a/models/repo/collaboration_test.go b/models/repo/collaboration_test.go index a29dfe99a5..461a2fdc57 100644 --- a/models/repo/collaboration_test.go +++ b/models/repo/collaboration_test.go @@ -11,6 +11,7 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" "github.com/stretchr/testify/assert" ) @@ -156,3 +157,23 @@ func TestRepo_GetCollaboration(t *testing.T) { assert.NoError(t, err) assert.Nil(t, collab) } + +func TestGetCollaboratorWithUser(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + user16 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 16}) + user15 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}) + user18 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 18}) + + collabs, err := repo_model.GetCollaboratorWithUser(db.DefaultContext, user16.ID, user15.ID) + assert.NoError(t, err) + assert.Len(t, collabs, 2) + assert.EqualValues(t, 5, collabs[0]) + assert.EqualValues(t, 7, collabs[1]) + + collabs, err = repo_model.GetCollaboratorWithUser(db.DefaultContext, user16.ID, user18.ID) + assert.NoError(t, err) + assert.Len(t, collabs, 2) + assert.EqualValues(t, 6, collabs[0]) + assert.EqualValues(t, 8, collabs[1]) +} diff --git a/services/user/block.go b/services/user/block.go index 05f9a376a7..06cdd27176 100644 --- a/services/user/block.go +++ b/services/user/block.go @@ -54,5 +54,17 @@ func BlockUser(ctx context.Context, userID, blockID int64) error { return err } + // Remove blocked user as collaborator from repositories the user owns as an + // individual. + collabsID, err := repo_model.GetCollaboratorWithUser(ctx, userID, blockID) + if err != nil { + return err + } + + _, err = db.GetEngine(ctx).In("id", collabsID).Delete(&repo_model.Collaboration{}) + if err != nil { + return err + } + return committer.Commit() } diff --git a/services/user/block_test.go b/services/user/block_test.go index 8a0a3c4739..af1c53f493 100644 --- a/services/user/block_test.go +++ b/services/user/block_test.go @@ -22,20 +22,52 @@ func TestBlockUser(t *testing.T) { doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - // Follow each other. - assert.NoError(t, user_model.FollowUser(db.DefaultContext, doer.ID, blockedUser.ID)) - assert.NoError(t, user_model.FollowUser(db.DefaultContext, blockedUser.ID, doer.ID)) + t.Run("Follow", func(t *testing.T) { + defer user_model.UnblockUser(db.DefaultContext, doer.ID, blockedUser.ID) - // Blocked user watch repository of doer. - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: doer.ID}) - assert.NoError(t, repo_model.WatchRepo(db.DefaultContext, blockedUser.ID, repo.ID, true)) + // Follow each other. + assert.NoError(t, user_model.FollowUser(db.DefaultContext, doer.ID, blockedUser.ID)) + assert.NoError(t, user_model.FollowUser(db.DefaultContext, blockedUser.ID, doer.ID)) - assert.NoError(t, BlockUser(db.DefaultContext, doer.ID, blockedUser.ID)) + assert.NoError(t, BlockUser(db.DefaultContext, doer.ID, blockedUser.ID)) - // Ensure they aren't following each other anymore. - assert.False(t, user_model.IsFollowing(doer.ID, blockedUser.ID)) - assert.False(t, user_model.IsFollowing(blockedUser.ID, doer.ID)) + // Ensure they aren't following each other anymore. + assert.False(t, user_model.IsFollowing(doer.ID, blockedUser.ID)) + assert.False(t, user_model.IsFollowing(blockedUser.ID, doer.ID)) + }) - // Ensure blocked user isn't following doer's repository. - assert.False(t, repo_model.IsWatching(blockedUser.ID, repo.ID)) + t.Run("Watch", func(t *testing.T) { + defer user_model.UnblockUser(db.DefaultContext, doer.ID, blockedUser.ID) + + // Blocked user watch repository of doer. + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: doer.ID}) + assert.NoError(t, repo_model.WatchRepo(db.DefaultContext, blockedUser.ID, repo.ID, true)) + + assert.NoError(t, BlockUser(db.DefaultContext, doer.ID, blockedUser.ID)) + + // Ensure blocked user isn't following doer's repository. + assert.False(t, repo_model.IsWatching(blockedUser.ID, repo.ID)) + }) + + t.Run("Collaboration", func(t *testing.T) { + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 16}) + blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 18}) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22, OwnerID: doer.ID}) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21, OwnerID: doer.ID}) + defer user_model.UnblockUser(db.DefaultContext, doer.ID, blockedUser.ID) + + isBlockedUserCollab := func(repo *repo_model.Repository) bool { + isCollaborator, err := repo_model.IsCollaborator(db.DefaultContext, repo.ID, blockedUser.ID) + assert.NoError(t, err) + return isCollaborator + } + + assert.True(t, isBlockedUserCollab(repo1)) + assert.True(t, isBlockedUserCollab(repo2)) + + assert.NoError(t, BlockUser(db.DefaultContext, doer.ID, blockedUser.ID)) + + assert.False(t, isBlockedUserCollab(repo1)) + assert.False(t, isBlockedUserCollab(repo2)) + }) }