Skip to content

Commit

Permalink
Delete project member when delete project (#19523)
Browse files Browse the repository at this point in the history
Signed-off-by: stonezdj <daojunz@vmware.com>
  • Loading branch information
stonezdj authored Nov 8, 2023
1 parent bfd44b9 commit da949bf
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 6 deletions.
12 changes: 6 additions & 6 deletions src/controller/event/handler/internal/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/goharbor/harbor/src/controller/immutable"
"github.com/goharbor/harbor/src/controller/retention"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/pkg/member"
)

// ProjectEventHandler process project event data
Expand All @@ -39,16 +40,15 @@ func (a *ProjectEventHandler) IsStateful() bool {

func (a *ProjectEventHandler) onProjectDelete(ctx context.Context, event *event.DeleteProjectEvent) error {
log.Infof("delete project id: %d", event.ProjectID)
// delete tag immutable
err := immutable.Ctr.DeleteImmutableRuleByProject(ctx, event.ProjectID)
if err != nil {
if err := immutable.Ctr.DeleteImmutableRuleByProject(ctx, event.ProjectID); err != nil {
log.Errorf("failed to delete immutable rule, error %v", err)
}
// delete tag retention
err = retention.Ctl.DeleteRetentionByProject(ctx, event.ProjectID)
if err != nil {
if err := retention.Ctl.DeleteRetentionByProject(ctx, event.ProjectID); err != nil {
log.Errorf("failed to delete retention rule, error %v", err)
}
if err := member.Mgr.DeleteMemberByProjectID(ctx, event.ProjectID); err != nil {
log.Errorf("failed to delete project member, error %v", err)
}
return nil
}

Expand Down
22 changes: 22 additions & 0 deletions src/controller/event/handler/internal/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,24 @@ import (
beegoorm "github.com/beego/beego/v2/client/orm"
"github.com/stretchr/testify/suite"

"github.com/goharbor/harbor/src/common"
common_dao "github.com/goharbor/harbor/src/common/dao"
commonmodels "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/controller/event"
"github.com/goharbor/harbor/src/controller/immutable"
"github.com/goharbor/harbor/src/lib/config"
"github.com/goharbor/harbor/src/lib/orm"
"github.com/goharbor/harbor/src/pkg"
"github.com/goharbor/harbor/src/pkg/artifact"
immutableModel "github.com/goharbor/harbor/src/pkg/immutable/model"
"github.com/goharbor/harbor/src/pkg/member"
memberModels "github.com/goharbor/harbor/src/pkg/member/models"
"github.com/goharbor/harbor/src/pkg/project"
"github.com/goharbor/harbor/src/pkg/project/models"
"github.com/goharbor/harbor/src/pkg/repository/model"
"github.com/goharbor/harbor/src/pkg/tag"
tagmodel "github.com/goharbor/harbor/src/pkg/tag/model/tag"
"github.com/goharbor/harbor/src/pkg/user"
)

// ProjectHandlerTestSuite is test suite for artifact handler.
Expand Down Expand Up @@ -81,6 +86,18 @@ func (suite *ProjectHandlerTestSuite) TestOnProjectDelete() {
projID, err := project.New().Create(suite.ctx, &models.Project{Name: "test-project", OwnerID: 1})
suite.Nil(err)

userID, err := user.Mgr.Create(suite.ctx, &commonmodels.User{Username: "test-user-event", Email: "test-user-event@example.com"})
defer user.Mgr.Delete(suite.ctx, userID)

// create project member
_, err = member.Mgr.AddProjectMember(suite.ctx, memberModels.Member{ProjectID: projID, EntityType: common.UserMember, EntityID: userID, Role: 1})
suite.Nil(err)

// verify project member
members, err := member.Mgr.SearchMemberByName(suite.ctx, projID, "test-user-event")
suite.Nil(err)
suite.Equal(1, len(members))

defer project.New().Delete(suite.ctx, projID)
immutableRule := &immutableModel.Metadata{
ProjectID: projID,
Expand Down Expand Up @@ -116,6 +133,11 @@ func (suite *ProjectHandlerTestSuite) TestOnProjectDelete() {
// check if immutable rule is deleted
_, err = immutable.Ctr.GetImmutableRule(suite.ctx, immutableID)
suite.NotNil(err)

// check if project member is deleted
mbs, err := member.Mgr.SearchMemberByName(suite.ctx, projID, "test-user-event")
suite.Nil(err)
suite.Equal(0, len(mbs))
}

// TestArtifactHandler tests ArtifactHandler.
Expand Down
14 changes: 14 additions & 0 deletions src/pkg/member/dao/dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type DAO interface {
DeleteProjectMemberByID(ctx context.Context, projectID int64, pmid int) error
// DeleteProjectMemberByUserID -- Delete project member by user id
DeleteProjectMemberByUserID(ctx context.Context, uid int) error
// DeleteProjectMemberByProjectID -- Delete project member by project id
DeleteProjectMemberByProjectID(ctx context.Context, projectID int64) error
// SearchMemberByName search members of the project by entity_name
SearchMemberByName(ctx context.Context, projectID int64, entityName string) ([]*models.Member, error)
// ListRoles lists the roles of user for the specific project
Expand Down Expand Up @@ -261,3 +263,15 @@ func (d *dao) ListRoles(ctx context.Context, user *models.User, projectID int64)
}
return roles, nil
}

func (d *dao) DeleteProjectMemberByProjectID(ctx context.Context, projectID int64) error {
o, err := orm.FromContext(ctx)
if err != nil {
return err
}
sql := "delete from project_member where project_id = ?"
if _, err := o.Raw(sql, projectID).Exec(); err != nil {
return err
}
return nil
}
54 changes: 54 additions & 0 deletions src/pkg/member/dao/dao_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package dao

import (
"database/sql"
"fmt"
"testing"

"github.com/stretchr/testify/suite"
Expand Down Expand Up @@ -293,6 +294,59 @@ func (s *DaoTestSuite) TestDeleteProjectMemberByUserId() {
s.Nil(err)
}

func (s *DaoTestSuite) TestDeleteProjectMemberByProjectID() {
s.WithUser(func(userID int64, username string) {
proj2, err := s.projectMgr.Get(s.Context(), "member_test_02")
s.Nil(err)
s.NotNil(proj2)
var addMember = models.Member{
ProjectID: proj2.ProjectID,
EntityID: int(userID),
EntityType: common.UserMember,
Role: common.RoleDeveloper,
}
pmid, err := s.dao.AddProjectMember(s.Context(), addMember)
s.Nil(err)
s.True(pmid > 0)

err = s.dao.DeleteProjectMemberByProjectID(s.Context(), proj2.ProjectID)
s.Nil(err)

queryMember := models.Member{ProjectID: proj2.ProjectID, EntityID: int(userID), EntityType: common.UserMember}

// not exist
members, err := s.dao.GetProjectMember(s.Context(), queryMember, nil)
s.True(len(members) == 0)
s.Nil(err)
}, "test_project_member_delete")
}

func (s *DaoTestSuite) WithUser(f func(int64, string), usernames ...string) {
var username string
if len(usernames) > 0 {
username = usernames[0]
} else {
username = s.RandString(5)
}

o, err := orm.FromContext(orm.Context())
if err != nil {
s.Fail("got error %v", err)
}

var userID int64

email := fmt.Sprintf("%s@example.com", username)
sql := "INSERT INTO harbor_user (username, realname, email, password) VALUES (?, ?, ?, 'Harbor12345') RETURNING user_id"
s.Nil(o.Raw(sql, username, username, email).QueryRow(&userID))

defer func() {
o.Raw("delete from harbor_user WHERE user_id = ?", userID).Exec()
}()

f(userID, username)
}

func TestDaoTestSuite(t *testing.T) {
suite.Run(t, &DaoTestSuite{})
}
5 changes: 5 additions & 0 deletions src/pkg/member/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type Manager interface {
SearchMemberByName(ctx context.Context, projectID int64, entityName string) ([]*models.Member, error)
// DeleteMemberByUserID delete project member by user id
DeleteMemberByUserID(ctx context.Context, uid int) error
// DeleteMemberByProjectID delete project member by project id
DeleteMemberByProjectID(ctx context.Context, projectID int64) error
// GetTotalOfProjectMembers get the total amount of project members
GetTotalOfProjectMembers(ctx context.Context, projectID int64, query *q.Query, roles ...int) (int, error)
// ListRoles list project roles
Expand Down Expand Up @@ -101,6 +103,9 @@ func (m *manager) Delete(ctx context.Context, projectID int64, memberID int) err
func (m *manager) DeleteMemberByUserID(ctx context.Context, uid int) error {
return m.dao.DeleteProjectMemberByUserID(ctx, uid)
}
func (m *manager) DeleteMemberByProjectID(ctx context.Context, projectID int64) error {
return m.dao.DeleteProjectMemberByProjectID(ctx, projectID)
}

// NewManager ...
func NewManager() Manager {
Expand Down
14 changes: 14 additions & 0 deletions src/testing/pkg/member/fake_member_manager.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit da949bf

Please sign in to comment.