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