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