@@ -1477,46 +1477,18 @@ func getParticipantsByIssueID(e Engine, issueID int64) ([]*User, error) {
1477
1477
return users , e .In ("id" , userIDs ).Find (& users )
1478
1478
}
1479
1479
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 {
1483
1482
if len (mentions ) == 0 {
1484
1483
return nil
1485
1484
}
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
1514
1488
}
1515
-
1516
1489
if err := UpdateIssueUsersByMentions (ctx , issueID , ids ); err != nil {
1517
1490
return fmt .Errorf ("UpdateIssueUsersByMentions: %v" , err )
1518
1491
}
1519
-
1520
1492
return nil
1521
1493
}
1522
1494
@@ -1909,3 +1881,120 @@ func (issue *Issue) updateClosedNum(e Engine) (err error) {
1909
1881
}
1910
1882
return
1911
1883
}
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