Nicely handle missing user in collaborations (#17049)

* Nicely handle missing user in collaborations

It is possible to have a collaboration in a repository which refers to a no-longer
existing user. This causes the repository transfer to fail with an unusual error.

This PR makes `repo.getCollaborators()` nicely handle the missing user by ghosting
the collaboration but also adds consistency check. It also adds an
Access consistency check.

Fix #17044

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
This commit is contained in:
zeripath
2021-09-27 19:07:19 +01:00
committed by GitHub
parent b5856c4437
commit e8574f2f7d
4 changed files with 177 additions and 274 deletions

View File

@ -230,6 +230,9 @@ func (repo *Repository) refreshCollaboratorAccesses(e db.Engine, accessMap map[i
return fmt.Errorf("getCollaborations: %v", err)
}
for _, c := range collaborators {
if c.User.IsGhost() {
continue
}
updateUserAccess(accessMap, c.User, c.Collaboration.Mode)
}
return nil

View File

@ -9,6 +9,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
@ -88,16 +89,21 @@ func (repo *Repository) getCollaborators(e db.Engine, listOptions db.ListOptions
return nil, fmt.Errorf("getCollaborations: %v", err)
}
collaborators := make([]*Collaborator, len(collaborations))
for i, c := range collaborations {
collaborators := make([]*Collaborator, 0, len(collaborations))
for _, c := range collaborations {
user, err := getUserByID(e, c.UserID)
if err != nil {
return nil, err
if IsErrUserNotExist(err) {
log.Warn("Inconsistent DB: User: %d is listed as collaborator of %-v but does not exist", c.UserID, repo)
user = NewGhostUser()
} else {
return nil, err
}
}
collaborators[i] = &Collaborator{
collaborators = append(collaborators, &Collaborator{
User: user,
Collaboration: c,
}
})
}
return collaborators, nil
}

View File

@ -274,6 +274,14 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err e
// Dummy object.
collaboration := &Collaboration{RepoID: repo.ID}
for _, c := range collaborators {
if c.IsGhost() {
collaboration.ID = c.Collaboration.ID
if _, err := sess.Delete(collaboration); err != nil {
return fmt.Errorf("remove collaborator '%d': %v", c.ID, err)
}
collaboration.ID = 0
}
if c.ID != newOwner.ID {
isMember, err := isOrganizationMember(sess, newOwner.ID, c.ID)
if err != nil {
@ -286,6 +294,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err e
if _, err := sess.Delete(collaboration); err != nil {
return fmt.Errorf("remove collaborator '%d': %v", c.ID, err)
}
collaboration.UserID = 0
}
// Remove old team-repository relations.

File diff suppressed because it is too large Load Diff