diff options
author | guillep2k <18600385+guillep2k@users.noreply.github.com> | 2019-10-10 13:45:11 -0300 |
---|---|---|
committer | Lauris BH <lauris@nix.lv> | 2019-10-10 19:45:11 +0300 |
commit | df2c11a878719719b8600745888c570af93827be (patch) | |
tree | 4dd527c9538a748483ee8c1467bd88ef8001a380 /models/issue.go | |
parent | 57b0d9a38ba7d8dcc05a74fe39ab9f9e765ed8b3 (diff) | |
download | gitea-df2c11a878719719b8600745888c570af93827be.tar.gz gitea-df2c11a878719719b8600745888c570af93827be.zip |
Ignore mentions for users with no access (#8395)
* Draft for ResolveMentionsByVisibility()
* Correct typo
* Resolve teams instead of orgs for mentions
* Create test for ResolveMentionsByVisibility
* Fix check for individual users and doer
* Test and fix team mentions
* Run all mentions through visibility filter
* Fix error check
* Simplify code, fix doer included in teams
* Simplify team id list build
Diffstat (limited to 'models/issue.go')
-rw-r--r-- | models/issue.go | 155 |
1 files changed, 122 insertions, 33 deletions
diff --git a/models/issue.go b/models/issue.go index e4cc1291c2..f8fa1377a8 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1477,46 +1477,18 @@ func getParticipantsByIssueID(e Engine, issueID int64) ([]*User, error) { return users, e.In("id", userIDs).Find(&users) } -// UpdateIssueMentions extracts mentioned people from content and -// updates issue-user relations for them. -func UpdateIssueMentions(ctx DBContext, issueID int64, mentions []string) error { +// UpdateIssueMentions updates issue-user relations for mentioned users. +func UpdateIssueMentions(ctx DBContext, issueID int64, mentions []*User) error { if len(mentions) == 0 { return nil } - - for i := range mentions { - mentions[i] = strings.ToLower(mentions[i]) - } - users := make([]*User, 0, len(mentions)) - - if err := ctx.e.In("lower_name", mentions).Asc("lower_name").Find(&users); err != nil { - return fmt.Errorf("find mentioned users: %v", err) - } - - ids := make([]int64, 0, len(mentions)) - for _, user := range users { - ids = append(ids, user.ID) - if !user.IsOrganization() || user.NumMembers == 0 { - continue - } - - memberIDs := make([]int64, 0, user.NumMembers) - orgUsers, err := getOrgUsersByOrgID(ctx.e, user.ID) - if err != nil { - return fmt.Errorf("GetOrgUsersByOrgID [%d]: %v", user.ID, err) - } - - for _, orgUser := range orgUsers { - memberIDs = append(memberIDs, orgUser.ID) - } - - ids = append(ids, memberIDs...) + ids := make([]int64, len(mentions)) + for i, u := range mentions { + ids[i] = u.ID } - if err := UpdateIssueUsersByMentions(ctx, issueID, ids); err != nil { return fmt.Errorf("UpdateIssueUsersByMentions: %v", err) } - return nil } @@ -1909,3 +1881,120 @@ func (issue *Issue) updateClosedNum(e Engine) (err error) { } return } + +// ResolveMentionsByVisibility returns the users mentioned in an issue, removing those that +// don't have access to reading it. Teams are expanded into their users, but organizations are ignored. +func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, mentions []string) (users []*User, err error) { + if len(mentions) == 0 { + return + } + if err = issue.loadRepo(ctx.e); err != nil { + return + } + resolved := make(map[string]bool, 20) + names := make([]string, 0, 20) + resolved[doer.LowerName] = true + for _, name := range mentions { + name := strings.ToLower(name) + if _, ok := resolved[name]; ok { + continue + } + resolved[name] = false + names = append(names, name) + } + + if err := issue.Repo.getOwner(ctx.e); err != nil { + return nil, err + } + + if issue.Repo.Owner.IsOrganization() { + // Since there can be users with names that match the name of a team, + // if the team exists and can read the issue, the team takes precedence. + teams := make([]*Team, 0, len(names)) + if err := ctx.e. + Join("INNER", "team_repo", "team_repo.team_id = team.id"). + Where("team_repo.repo_id=?", issue.Repo.ID). + In("team.lower_name", names). + Find(&teams); err != nil { + return nil, fmt.Errorf("find mentioned teams: %v", err) + } + if len(teams) != 0 { + checked := make([]int64, 0, len(teams)) + unittype := UnitTypeIssues + if issue.IsPull { + unittype = UnitTypePullRequests + } + for _, team := range teams { + if team.Authorize >= AccessModeOwner { + checked = append(checked, team.ID) + resolved[team.LowerName] = true + continue + } + has, err := ctx.e.Get(&TeamUnit{OrgID: issue.Repo.Owner.ID, TeamID: team.ID, Type: unittype}) + if err != nil { + return nil, fmt.Errorf("get team units (%d): %v", team.ID, err) + } + if has { + checked = append(checked, team.ID) + resolved[team.LowerName] = true + } + } + if len(checked) != 0 { + teamusers := make([]*User, 0, 20) + if err := ctx.e. + Join("INNER", "team_user", "team_user.uid = `user`.id"). + In("`team_user`.team_id", checked). + And("`user`.is_active = ?", true). + And("`user`.prohibit_login = ?", false). + Find(&teamusers); err != nil { + return nil, fmt.Errorf("get teams users: %v", err) + } + if len(teamusers) > 0 { + users = make([]*User, 0, len(teamusers)) + for _, user := range teamusers { + if already, ok := resolved[user.LowerName]; !ok || !already { + users = append(users, user) + resolved[user.LowerName] = true + } + } + } + } + } + + // Remove names already in the list to avoid querying the database if pending names remain + names = make([]string, 0, len(resolved)) + for name, already := range resolved { + if !already { + names = append(names, name) + } + } + if len(names) == 0 { + return + } + } + + unchecked := make([]*User, 0, len(names)) + if err := ctx.e. + Where("`user`.is_active = ?", true). + And("`user`.prohibit_login = ?", false). + In("`user`.lower_name", names). + Find(&unchecked); err != nil { + return nil, fmt.Errorf("find mentioned users: %v", err) + } + for _, user := range unchecked { + if already := resolved[user.LowerName]; already || user.IsOrganization() { + continue + } + // Normal users must have read access to the referencing issue + perm, err := getUserRepoPermission(ctx.e, issue.Repo, user) + if err != nil { + return nil, fmt.Errorf("getUserRepoPermission [%d]: %v", user.ID, err) + } + if !perm.CanReadIssuesOrPulls(issue.IsPull) { + continue + } + users = append(users, user) + } + + return +} |