You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

api_team_test.go 13KB

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