@@ -1477,46 +1477,18 @@ func getParticipantsByIssueID(e Engine, issueID int64) ([]*User, error) {
14771477 return users , e .In ("id" , userIDs ).Find (& users )
14781478}
14791479
1480- // UpdateIssueMentions extracts mentioned people from content and
1481- // updates issue-user relations for them.
1482- func UpdateIssueMentions (ctx DBContext , issueID int64 , mentions []string ) error {
1480+ // UpdateIssueMentions updates issue-user relations for mentioned users.
1481+ func UpdateIssueMentions (ctx DBContext , issueID int64 , mentions []* User ) error {
14831482 if len (mentions ) == 0 {
14841483 return nil
14851484 }
1486-
1487- for i := range mentions {
1488- mentions [i ] = strings .ToLower (mentions [i ])
1489- }
1490- users := make ([]* User , 0 , len (mentions ))
1491-
1492- if err := ctx .e .In ("lower_name" , mentions ).Asc ("lower_name" ).Find (& users ); err != nil {
1493- return fmt .Errorf ("find mentioned users: %v" , err )
1494- }
1495-
1496- ids := make ([]int64 , 0 , len (mentions ))
1497- for _ , user := range users {
1498- ids = append (ids , user .ID )
1499- if ! user .IsOrganization () || user .NumMembers == 0 {
1500- continue
1501- }
1502-
1503- memberIDs := make ([]int64 , 0 , user .NumMembers )
1504- orgUsers , err := getOrgUsersByOrgID (ctx .e , user .ID )
1505- if err != nil {
1506- return fmt .Errorf ("GetOrgUsersByOrgID [%d]: %v" , user .ID , err )
1507- }
1508-
1509- for _ , orgUser := range orgUsers {
1510- memberIDs = append (memberIDs , orgUser .ID )
1511- }
1512-
1513- ids = append (ids , memberIDs ... )
1485+ ids := make ([]int64 , len (mentions ))
1486+ for i , u := range mentions {
1487+ ids [i ] = u .ID
15141488 }
1515-
15161489 if err := UpdateIssueUsersByMentions (ctx , issueID , ids ); err != nil {
15171490 return fmt .Errorf ("UpdateIssueUsersByMentions: %v" , err )
15181491 }
1519-
15201492 return nil
15211493}
15221494
@@ -1909,3 +1881,120 @@ func (issue *Issue) updateClosedNum(e Engine) (err error) {
19091881 }
19101882 return
19111883}
1884+
1885+ // ResolveMentionsByVisibility returns the users mentioned in an issue, removing those that
1886+ // don't have access to reading it. Teams are expanded into their users, but organizations are ignored.
1887+ func (issue * Issue ) ResolveMentionsByVisibility (ctx DBContext , doer * User , mentions []string ) (users []* User , err error ) {
1888+ if len (mentions ) == 0 {
1889+ return
1890+ }
1891+ if err = issue .loadRepo (ctx .e ); err != nil {
1892+ return
1893+ }
1894+ resolved := make (map [string ]bool , 20 )
1895+ names := make ([]string , 0 , 20 )
1896+ resolved [doer .LowerName ] = true
1897+ for _ , name := range mentions {
1898+ name := strings .ToLower (name )
1899+ if _ , ok := resolved [name ]; ok {
1900+ continue
1901+ }
1902+ resolved [name ] = false
1903+ names = append (names , name )
1904+ }
1905+
1906+ if err := issue .Repo .getOwner (ctx .e ); err != nil {
1907+ return nil , err
1908+ }
1909+
1910+ if issue .Repo .Owner .IsOrganization () {
1911+ // Since there can be users with names that match the name of a team,
1912+ // if the team exists and can read the issue, the team takes precedence.
1913+ teams := make ([]* Team , 0 , len (names ))
1914+ if err := ctx .e .
1915+ Join ("INNER" , "team_repo" , "team_repo.team_id = team.id" ).
1916+ Where ("team_repo.repo_id=?" , issue .Repo .ID ).
1917+ In ("team.lower_name" , names ).
1918+ Find (& teams ); err != nil {
1919+ return nil , fmt .Errorf ("find mentioned teams: %v" , err )
1920+ }
1921+ if len (teams ) != 0 {
1922+ checked := make ([]int64 , 0 , len (teams ))
1923+ unittype := UnitTypeIssues
1924+ if issue .IsPull {
1925+ unittype = UnitTypePullRequests
1926+ }
1927+ for _ , team := range teams {
1928+ if team .Authorize >= AccessModeOwner {
1929+ checked = append (checked , team .ID )
1930+ resolved [team .LowerName ] = true
1931+ continue
1932+ }
1933+ has , err := ctx .e .Get (& TeamUnit {OrgID : issue .Repo .Owner .ID , TeamID : team .ID , Type : unittype })
1934+ if err != nil {
1935+ return nil , fmt .Errorf ("get team units (%d): %v" , team .ID , err )
1936+ }
1937+ if has {
1938+ checked = append (checked , team .ID )
1939+ resolved [team .LowerName ] = true
1940+ }
1941+ }
1942+ if len (checked ) != 0 {
1943+ teamusers := make ([]* User , 0 , 20 )
1944+ if err := ctx .e .
1945+ Join ("INNER" , "team_user" , "team_user.uid = `user`.id" ).
1946+ In ("`team_user`.team_id" , checked ).
1947+ And ("`user`.is_active = ?" , true ).
1948+ And ("`user`.prohibit_login = ?" , false ).
1949+ Find (& teamusers ); err != nil {
1950+ return nil , fmt .Errorf ("get teams users: %v" , err )
1951+ }
1952+ if len (teamusers ) > 0 {
1953+ users = make ([]* User , 0 , len (teamusers ))
1954+ for _ , user := range teamusers {
1955+ if already , ok := resolved [user .LowerName ]; ! ok || ! already {
1956+ users = append (users , user )
1957+ resolved [user .LowerName ] = true
1958+ }
1959+ }
1960+ }
1961+ }
1962+ }
1963+
1964+ // Remove names already in the list to avoid querying the database if pending names remain
1965+ names = make ([]string , 0 , len (resolved ))
1966+ for name , already := range resolved {
1967+ if ! already {
1968+ names = append (names , name )
1969+ }
1970+ }
1971+ if len (names ) == 0 {
1972+ return
1973+ }
1974+ }
1975+
1976+ unchecked := make ([]* User , 0 , len (names ))
1977+ if err := ctx .e .
1978+ Where ("`user`.is_active = ?" , true ).
1979+ And ("`user`.prohibit_login = ?" , false ).
1980+ In ("`user`.lower_name" , names ).
1981+ Find (& unchecked ); err != nil {
1982+ return nil , fmt .Errorf ("find mentioned users: %v" , err )
1983+ }
1984+ for _ , user := range unchecked {
1985+ if already := resolved [user .LowerName ]; already || user .IsOrganization () {
1986+ continue
1987+ }
1988+ // Normal users must have read access to the referencing issue
1989+ perm , err := getUserRepoPermission (ctx .e , issue .Repo , user )
1990+ if err != nil {
1991+ return nil , fmt .Errorf ("getUserRepoPermission [%d]: %v" , user .ID , err )
1992+ }
1993+ if ! perm .CanReadIssuesOrPulls (issue .IsPull ) {
1994+ continue
1995+ }
1996+ users = append (users , user )
1997+ }
1998+
1999+ return
2000+ }
0 commit comments