gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "fmt"
  6. "net/http"
  7. "sort"
  8. "testing"
  9. auth_model "code.gitea.io/gitea/models/auth"
  10. "code.gitea.io/gitea/models/organization"
  11. "code.gitea.io/gitea/models/perm"
  12. "code.gitea.io/gitea/models/repo"
  13. "code.gitea.io/gitea/models/unit"
  14. "code.gitea.io/gitea/models/unittest"
  15. user_model "code.gitea.io/gitea/models/user"
  16. api "code.gitea.io/gitea/modules/structs"
  17. "code.gitea.io/gitea/services/convert"
  18. "code.gitea.io/gitea/tests"
  19. "github.com/stretchr/testify/assert"
  20. )
  21. func TestAPITeam(t *testing.T) {
  22. defer tests.PrepareTestEnv(t)()
  23. teamUser := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 1})
  24. team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamUser.TeamID})
  25. org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: teamUser.OrgID})
  26. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser.UID})
  27. session := loginUser(t, user.Name)
  28. token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization)
  29. req := NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID).
  30. AddTokenAuth(token)
  31. resp := MakeRequest(t, req, http.StatusOK)
  32. var apiTeam api.Team
  33. DecodeJSON(t, resp, &apiTeam)
  34. assert.Equal(t, team.ID, apiTeam.ID)
  35. assert.Equal(t, team.Name, apiTeam.Name)
  36. assert.Equal(t, convert.ToOrganization(t.Context(), org), apiTeam.Organization)
  37. // non team member user will not access the teams details
  38. teamUser2 := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 3})
  39. user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser2.UID})
  40. session = loginUser(t, user2.Name)
  41. token = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization)
  42. req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID).
  43. AddTokenAuth(token)
  44. _ = MakeRequest(t, req, http.StatusForbidden)
  45. req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID)
  46. _ = MakeRequest(t, req, http.StatusUnauthorized)
  47. // Get an admin user able to create, update and delete teams.
  48. user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
  49. session = loginUser(t, user.Name)
  50. token = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization)
  51. org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 6})
  52. // Create team.
  53. teamToCreate := &api.CreateTeamOption{
  54. Name: "team1",
  55. Description: "team one",
  56. IncludesAllRepositories: true,
  57. Permission: "write",
  58. Units: []string{"repo.code", "repo.issues"},
  59. }
  60. req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", org.Name), teamToCreate).
  61. AddTokenAuth(token)
  62. resp = MakeRequest(t, req, http.StatusCreated)
  63. apiTeam = api.Team{}
  64. DecodeJSON(t, resp, &apiTeam)
  65. checkTeamResponse(t, "CreateTeam1", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
  66. "none", teamToCreate.Units, nil)
  67. checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
  68. "none", teamToCreate.Units, nil)
  69. teamID := apiTeam.ID
  70. // Edit team.
  71. editDescription := "team 1"
  72. editFalse := false
  73. teamToEdit := &api.EditTeamOption{
  74. Name: "teamone",
  75. Description: &editDescription,
  76. Permission: "admin",
  77. IncludesAllRepositories: &editFalse,
  78. Units: []string{"repo.code", "repo.pulls", "repo.releases"},
  79. }
  80. req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEdit).
  81. AddTokenAuth(token)
  82. resp = MakeRequest(t, req, http.StatusOK)
  83. apiTeam = api.Team{}
  84. DecodeJSON(t, resp, &apiTeam)
  85. checkTeamResponse(t, "EditTeam1", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
  86. teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
  87. checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
  88. teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
  89. // Edit team Description only
  90. editDescription = "first team"
  91. teamToEditDesc := api.EditTeamOption{Description: &editDescription}
  92. req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEditDesc).
  93. AddTokenAuth(token)
  94. resp = MakeRequest(t, req, http.StatusOK)
  95. apiTeam = api.Team{}
  96. DecodeJSON(t, resp, &apiTeam)
  97. checkTeamResponse(t, "EditTeam1_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
  98. teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
  99. checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
  100. teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
  101. // Read team.
  102. teamRead := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
  103. assert.NoError(t, teamRead.LoadUnits(t.Context()))
  104. req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamID).
  105. AddTokenAuth(token)
  106. resp = MakeRequest(t, req, http.StatusOK)
  107. apiTeam = api.Team{}
  108. DecodeJSON(t, resp, &apiTeam)
  109. checkTeamResponse(t, "ReadTeam1", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories,
  110. teamRead.AccessMode.ToString(), teamRead.GetUnitNames(), teamRead.GetUnitsMap())
  111. // Delete team.
  112. req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID).
  113. AddTokenAuth(token)
  114. MakeRequest(t, req, http.StatusNoContent)
  115. unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
  116. // create team again via UnitsMap
  117. // Create team.
  118. teamToCreate = &api.CreateTeamOption{
  119. Name: "team2",
  120. Description: "team two",
  121. IncludesAllRepositories: true,
  122. Permission: "write",
  123. UnitsMap: map[string]string{"repo.code": "read", "repo.issues": "write", "repo.wiki": "none"},
  124. }
  125. req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", org.Name), teamToCreate).
  126. AddTokenAuth(token)
  127. resp = MakeRequest(t, req, http.StatusCreated)
  128. apiTeam = api.Team{}
  129. DecodeJSON(t, resp, &apiTeam)
  130. checkTeamResponse(t, "CreateTeam2", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
  131. "none", nil, teamToCreate.UnitsMap)
  132. checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
  133. "none", nil, teamToCreate.UnitsMap)
  134. teamID = apiTeam.ID
  135. // Edit team.
  136. editDescription = "team 1"
  137. editFalse = false
  138. teamToEdit = &api.EditTeamOption{
  139. Name: "teamtwo",
  140. Description: &editDescription,
  141. Permission: "write",
  142. IncludesAllRepositories: &editFalse,
  143. UnitsMap: map[string]string{"repo.code": "read", "repo.pulls": "read", "repo.releases": "write"},
  144. }
  145. req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEdit).
  146. AddTokenAuth(token)
  147. resp = MakeRequest(t, req, http.StatusOK)
  148. apiTeam = api.Team{}
  149. DecodeJSON(t, resp, &apiTeam)
  150. checkTeamResponse(t, "EditTeam2", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
  151. "none", nil, teamToEdit.UnitsMap)
  152. checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
  153. "none", nil, teamToEdit.UnitsMap)
  154. // Edit team Description only
  155. editDescription = "second team"
  156. teamToEditDesc = api.EditTeamOption{Description: &editDescription}
  157. req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEditDesc).
  158. AddTokenAuth(token)
  159. resp = MakeRequest(t, req, http.StatusOK)
  160. apiTeam = api.Team{}
  161. DecodeJSON(t, resp, &apiTeam)
  162. checkTeamResponse(t, "EditTeam2_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
  163. "none", nil, teamToEdit.UnitsMap)
  164. checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
  165. "none", nil, teamToEdit.UnitsMap)
  166. // Read team.
  167. teamRead = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
  168. req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamID).
  169. AddTokenAuth(token)
  170. resp = MakeRequest(t, req, http.StatusOK)
  171. apiTeam = api.Team{}
  172. DecodeJSON(t, resp, &apiTeam)
  173. assert.NoError(t, teamRead.LoadUnits(t.Context()))
  174. checkTeamResponse(t, "ReadTeam2", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories,
  175. teamRead.AccessMode.ToString(), teamRead.GetUnitNames(), teamRead.GetUnitsMap())
  176. // Delete team.
  177. req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID).
  178. AddTokenAuth(token)
  179. MakeRequest(t, req, http.StatusNoContent)
  180. unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
  181. // Create admin team
  182. teamToCreate = &api.CreateTeamOption{
  183. Name: "teamadmin",
  184. Description: "team admin",
  185. IncludesAllRepositories: true,
  186. Permission: "admin",
  187. }
  188. req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", org.Name), teamToCreate).
  189. AddTokenAuth(token)
  190. resp = MakeRequest(t, req, http.StatusCreated)
  191. apiTeam = api.Team{}
  192. DecodeJSON(t, resp, &apiTeam)
  193. for _, ut := range unit.AllRepoUnitTypes {
  194. up := perm.AccessModeAdmin
  195. if ut == unit.TypeExternalTracker || ut == unit.TypeExternalWiki {
  196. up = perm.AccessModeRead
  197. }
  198. unittest.AssertExistsAndLoadBean(t, &organization.TeamUnit{
  199. OrgID: org.ID,
  200. TeamID: apiTeam.ID,
  201. Type: ut,
  202. AccessMode: up,
  203. })
  204. }
  205. teamID = apiTeam.ID
  206. // Delete team.
  207. req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID).
  208. AddTokenAuth(token)
  209. MakeRequest(t, req, http.StatusNoContent)
  210. unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
  211. }
  212. func checkTeamResponse(t *testing.T, testName string, apiTeam *api.Team, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) {
  213. t.Run(testName, func(t *testing.T) {
  214. assert.Equal(t, name, apiTeam.Name, "name")
  215. assert.Equal(t, description, apiTeam.Description, "description")
  216. assert.Equal(t, includesAllRepositories, apiTeam.IncludesAllRepositories, "includesAllRepositories")
  217. assert.Equal(t, permission, apiTeam.Permission, "permission")
  218. if units != nil {
  219. sort.StringSlice(units).Sort()
  220. sort.StringSlice(apiTeam.Units).Sort()
  221. assert.Equal(t, units, apiTeam.Units, "units")
  222. }
  223. if unitsMap != nil {
  224. assert.Equal(t, unitsMap, apiTeam.UnitsMap, "unitsMap")
  225. }
  226. })
  227. }
  228. func checkTeamBean(t *testing.T, id int64, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) {
  229. team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: id})
  230. assert.NoError(t, team.LoadUnits(t.Context()), "LoadUnits")
  231. apiTeam, err := convert.ToTeam(t.Context(), team)
  232. assert.NoError(t, err)
  233. checkTeamResponse(t, fmt.Sprintf("checkTeamBean/%s_%s", name, description), apiTeam, name, description, includesAllRepositories, permission, units, unitsMap)
  234. }
  235. type TeamSearchResults struct {
  236. OK bool `json:"ok"`
  237. Data []*api.Team `json:"data"`
  238. }
  239. func TestAPITeamSearch(t *testing.T) {
  240. defer tests.PrepareTestEnv(t)()
  241. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  242. org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17})
  243. var results TeamSearchResults
  244. token := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadOrganization)
  245. req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "_team").
  246. AddTokenAuth(token)
  247. resp := MakeRequest(t, req, http.StatusOK)
  248. DecodeJSON(t, resp, &results)
  249. assert.NotEmpty(t, results.Data)
  250. assert.Len(t, results.Data, 1)
  251. assert.Equal(t, "test_team", results.Data[0].Name)
  252. // no access if not organization member
  253. user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
  254. token5 := getUserToken(t, user5.Name, auth_model.AccessTokenScopeReadOrganization)
  255. req = NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "team").
  256. AddTokenAuth(token5)
  257. MakeRequest(t, req, http.StatusForbidden)
  258. }
  259. func TestAPIGetTeamRepo(t *testing.T) {
  260. defer tests.PrepareTestEnv(t)()
  261. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
  262. teamRepo := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 24})
  263. team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5})
  264. var results api.Repository
  265. token := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadOrganization)
  266. req := NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/", team.ID, teamRepo.FullName()).
  267. AddTokenAuth(token)
  268. resp := MakeRequest(t, req, http.StatusOK)
  269. DecodeJSON(t, resp, &results)
  270. assert.Equal(t, "big_test_private_4", teamRepo.Name)
  271. // no access if not organization member
  272. user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
  273. token5 := getUserToken(t, user5.Name, auth_model.AccessTokenScopeReadOrganization)
  274. req = NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/", team.ID, teamRepo.FullName()).
  275. AddTokenAuth(token5)
  276. MakeRequest(t, req, http.StatusNotFound)
  277. }